mirror of
https://github.com/holub/mame
synced 2025-04-18 22:49:58 +03:00
ti99_8: Chipset low-level emulation; ti99_4x: using new GROMs
This commit is contained in:
parent
35eab35778
commit
13fce89d59
@ -2029,8 +2029,6 @@ if (BUSES["TI99X"]~=null) then
|
||||
MAME_DIR .. "src/devices/bus/ti99x/datamux.h",
|
||||
MAME_DIR .. "src/devices/bus/ti99x/genboard.cpp",
|
||||
MAME_DIR .. "src/devices/bus/ti99x/genboard.h",
|
||||
MAME_DIR .. "src/devices/bus/ti99x/grom.cpp",
|
||||
MAME_DIR .. "src/devices/bus/ti99x/grom.h",
|
||||
MAME_DIR .. "src/devices/bus/ti99x/gromport.cpp",
|
||||
MAME_DIR .. "src/devices/bus/ti99x/gromport.h",
|
||||
MAME_DIR .. "src/devices/bus/ti99x/handset.cpp",
|
||||
|
@ -92,43 +92,87 @@
|
||||
|
||||
#define ACTIVE_TAG "ACTIVE"
|
||||
|
||||
#define LOG logerror
|
||||
#define VERBOSE 1
|
||||
#define TRACE_ROM 0
|
||||
#define TRACE_GROM 0
|
||||
#define TRACE_CRU 0
|
||||
#define TRACE_SWITCH 0
|
||||
|
||||
ti_pcode_card_device::ti_pcode_card_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: ti_expansion_card_device(mconfig, TI99_P_CODE, "TI-99 P-Code Card", tag, owner, clock, "ti99_pcode", __FILE__), m_rom(nullptr), m_bank_select(0), m_switch(false)
|
||||
: ti_expansion_card_device(mconfig, TI99_P_CODE, "TI-99 P-Code Card", tag, owner, clock, "ti99_pcode", __FILE__),
|
||||
m_rom(nullptr),
|
||||
m_bank_select(0),
|
||||
m_active(false),
|
||||
m_clock_count(0),
|
||||
m_clockhigh(false),
|
||||
m_inDsrArea(false),
|
||||
m_isrom0(false),
|
||||
m_isrom12(false),
|
||||
m_isgrom(false),
|
||||
m_address(0)
|
||||
{
|
||||
}
|
||||
|
||||
SETADDRESS_DBIN_MEMBER( ti_pcode_card_device::setaddress_dbin )
|
||||
{
|
||||
// Do not allow setaddress for the debugger. It will mess up the
|
||||
// setaddress/memory access pairs when the CPU enters wait states.
|
||||
if (space.debugger_access()) return;
|
||||
|
||||
m_address = offset;
|
||||
m_inDsrArea = ((m_address & m_select_mask)==m_select_value);
|
||||
|
||||
line_state a14 = ((m_address & 2)!=0)? ASSERT_LINE : CLEAR_LINE;
|
||||
|
||||
m_isrom0 = ((m_address & 0xf000)==0x4000);
|
||||
m_isrom12 = ((m_address & 0xf000)==0x5000);
|
||||
|
||||
// Valid access (GROM write with DBIN=0 or read with DBIN=1)
|
||||
bool validaccess = (state==CLEAR_LINE || (m_address & 0x0400)==0);
|
||||
|
||||
// GROM access 0101 1011 1111 1100
|
||||
m_isgrom = ((m_address & 0xfbfd)==0x5bfc) && validaccess;
|
||||
|
||||
if (validaccess)
|
||||
{
|
||||
int lines = (state==ASSERT_LINE)? 1 : 0;
|
||||
if (a14==ASSERT_LINE) lines |= 2;
|
||||
line_state select = m_isgrom? ASSERT_LINE : CLEAR_LINE;
|
||||
|
||||
// always deliver to GROM so that the select line may be cleared
|
||||
for (int i=0; i < 8; i++)
|
||||
m_grom[i]->set_lines(space, lines, select);
|
||||
}
|
||||
}
|
||||
|
||||
READ8Z_MEMBER( ti_pcode_card_device::readz )
|
||||
{
|
||||
if (m_switch && m_selected && ((offset & m_select_mask)==m_select_value))
|
||||
if (m_active && m_inDsrArea && m_selected)
|
||||
{
|
||||
// GROM access
|
||||
if ((offset & GROMMASK)==GROMREAD)
|
||||
if (m_isrom0)
|
||||
{
|
||||
for (auto & elem : m_grom) elem->readz(space, offset, value, mem_mask);
|
||||
if (VERBOSE>5) LOG("ti99_pcode: read from grom %04x: %02x\n", offset&0xffff, *value);
|
||||
*value = m_rom[m_address & 0x0fff];
|
||||
if (TRACE_ROM) logerror("Read from rom %04x: %02x\n", offset&0xffff, *value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((offset & 0x1000) == 0x0000)
|
||||
if (m_isgrom)
|
||||
{
|
||||
/* Accesses ROM 4732 (4K) */
|
||||
// 0000 xxxx xxxx xxxx
|
||||
*value = m_rom[offset & 0x0fff];
|
||||
if (VERBOSE>5) LOG("ti99_pcode: read from rom %04x: %02x\n", offset&0xffff, *value);
|
||||
for (auto& elem : m_grom) elem->readz(space, m_address, value);
|
||||
if (TRACE_GROM) logerror("Read from grom %04x: %02x\n", m_address&0xffff, *value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Accesses ROM 4764 (2*4K)
|
||||
// We have two banks here which are activated according
|
||||
// to the setting of CRU bit 4
|
||||
// Bank 0 is the ROM above
|
||||
// 0001 xxxx xxxx xxxx Bank 1
|
||||
// 0010 xxxx xxxx xxxx Bank 2
|
||||
*value = m_rom[(m_bank_select<<12) | (offset & 0x0fff)];
|
||||
if (VERBOSE>5) LOG("ti99_pcode: read from rom %04x (%02x): %02x\n", offset&0xffff, m_bank_select, *value);
|
||||
if (m_isrom12)
|
||||
{
|
||||
// Accesses ROM 4764 (2*4K)
|
||||
// We have two banks here which are activated according
|
||||
// to the setting of CRU bit 4
|
||||
// Bank 0 is the ROM above
|
||||
// 0001 xxxx xxxx xxxx Bank 1
|
||||
// 0010 xxxx xxxx xxxx Bank 2
|
||||
*value = m_rom[(m_bank_select<<12) | (m_address & 0x0fff)];
|
||||
if (TRACE_ROM) logerror("Read from rom %04x (%02x): %02x\n", m_address&0xffff, m_bank_select, *value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,34 +184,36 @@ READ8Z_MEMBER( ti_pcode_card_device::readz )
|
||||
*/
|
||||
WRITE8_MEMBER( ti_pcode_card_device::write )
|
||||
{
|
||||
if (m_switch && m_selected)
|
||||
if (m_active && m_isgrom && m_selected)
|
||||
{
|
||||
if ((offset & m_select_mask)==m_select_value)
|
||||
{
|
||||
if (VERBOSE>5) LOG("ti99_pcode: write to address %04x: %02x\n", offset & 0xffff, data);
|
||||
// 0101 1111 1111 11x0
|
||||
if ((offset & GROMMASK) == GROMWRITE)
|
||||
{
|
||||
for (auto & elem : m_grom) elem->write(space, offset, data, mem_mask);
|
||||
}
|
||||
}
|
||||
for (auto & elem : m_grom) elem->write(space, m_address, data);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Common READY* line from the GROMs.
|
||||
At this time we do not emulate GROM READY* since the CPU emulation does
|
||||
not yet process READY*. If it did, however, we would have to do a similar
|
||||
handling as in peribox (with INTA*): The common READY* line is a logical
|
||||
AND of all single READY lines. If any GROM pulls it down, the line goes
|
||||
down, and only if all GROMs release it, it pulls up again. We should think
|
||||
about a general solution.
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti_pcode_card_device::ready_line )
|
||||
{
|
||||
m_slot->set_ready(state);
|
||||
}
|
||||
|
||||
/*
|
||||
CLKOUT line from the CPU. This line is divided by 8 to generate a 375 Khz
|
||||
clock input for the GROMs, which are thus running at a lower rate than
|
||||
those in the console driven by the VDP (477 kHz).
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti_pcode_card_device::clock_in)
|
||||
{
|
||||
m_clock_count = (m_clock_count+1) & 0x03; // four pulses high, four pulses low
|
||||
if (m_clock_count==0)
|
||||
{
|
||||
// Toggle
|
||||
m_clockhigh = !m_clockhigh;
|
||||
for (auto & elem : m_grom) elem->gclock_in(m_clockhigh? ASSERT_LINE : CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
CRU read handler. The P-Code card does not offer CRU read lines, so
|
||||
we just ignore any request. (Note that CRU lines are not like memory; you
|
||||
@ -198,55 +244,22 @@ WRITE8_MEMBER(ti_pcode_card_device::cruwrite)
|
||||
if (addr==0x80) // Bit 4 is on address line 8
|
||||
{
|
||||
m_bank_select = (data+1); // we're calling this bank 1 and bank 2
|
||||
if (VERBOSE>5) LOG("ti99_pcode: select rom bank %d\n", m_bank_select);
|
||||
if (TRACE_CRU) logerror("Select rom bank %d\n", m_bank_select);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static GROM_CONFIG(pgrom0_config)
|
||||
{
|
||||
false, 0, PCODE_GROM_TAG, 0x0000, 0x1800, GROMFREQ
|
||||
};
|
||||
static GROM_CONFIG(pgrom1_config)
|
||||
{
|
||||
false, 1, PCODE_GROM_TAG, 0x2000, 0x1800, GROMFREQ
|
||||
};
|
||||
static GROM_CONFIG(pgrom2_config)
|
||||
{
|
||||
false, 2, PCODE_GROM_TAG, 0x4000, 0x1800, GROMFREQ
|
||||
};
|
||||
static GROM_CONFIG(pgrom3_config)
|
||||
{
|
||||
false, 3, PCODE_GROM_TAG, 0x6000, 0x1800, GROMFREQ
|
||||
};
|
||||
static GROM_CONFIG(pgrom4_config)
|
||||
{
|
||||
false, 4, PCODE_GROM_TAG, 0x8000, 0x1800, GROMFREQ
|
||||
};
|
||||
static GROM_CONFIG(pgrom5_config)
|
||||
{
|
||||
false, 5, PCODE_GROM_TAG, 0xa000, 0x1800, GROMFREQ
|
||||
};
|
||||
static GROM_CONFIG(pgrom6_config)
|
||||
{
|
||||
false, 6, PCODE_GROM_TAG, 0xc000, 0x1800, GROMFREQ
|
||||
};
|
||||
static GROM_CONFIG(pgrom7_config)
|
||||
{
|
||||
false, 7, PCODE_GROM_TAG, 0xe000, 0x1800, GROMFREQ
|
||||
};
|
||||
|
||||
void ti_pcode_card_device::device_start()
|
||||
{
|
||||
m_cru_base = 0x1f00;
|
||||
m_grom[0] = static_cast<ti99_grom_device*>(subdevice(PGROM0_TAG));
|
||||
m_grom[1] = static_cast<ti99_grom_device*>(subdevice(PGROM1_TAG));
|
||||
m_grom[2] = static_cast<ti99_grom_device*>(subdevice(PGROM2_TAG));
|
||||
m_grom[3] = static_cast<ti99_grom_device*>(subdevice(PGROM3_TAG));
|
||||
m_grom[4] = static_cast<ti99_grom_device*>(subdevice(PGROM4_TAG));
|
||||
m_grom[5] = static_cast<ti99_grom_device*>(subdevice(PGROM5_TAG));
|
||||
m_grom[6] = static_cast<ti99_grom_device*>(subdevice(PGROM6_TAG));
|
||||
m_grom[7] = static_cast<ti99_grom_device*>(subdevice(PGROM7_TAG));
|
||||
m_grom[0] = downcast<tmc0430_device*>(subdevice(PGROM0_TAG));
|
||||
m_grom[1] = downcast<tmc0430_device*>(subdevice(PGROM1_TAG));
|
||||
m_grom[2] = downcast<tmc0430_device*>(subdevice(PGROM2_TAG));
|
||||
m_grom[3] = downcast<tmc0430_device*>(subdevice(PGROM3_TAG));
|
||||
m_grom[4] = downcast<tmc0430_device*>(subdevice(PGROM4_TAG));
|
||||
m_grom[5] = downcast<tmc0430_device*>(subdevice(PGROM5_TAG));
|
||||
m_grom[6] = downcast<tmc0430_device*>(subdevice(PGROM6_TAG));
|
||||
m_grom[7] = downcast<tmc0430_device*>(subdevice(PGROM7_TAG));
|
||||
m_rom = memregion(PCODE_ROM_TAG)->base();
|
||||
}
|
||||
|
||||
@ -264,8 +277,15 @@ void ti_pcode_card_device::device_reset()
|
||||
}
|
||||
m_bank_select = 1;
|
||||
m_selected = false;
|
||||
m_clock_count = 0;
|
||||
m_clockhigh = false;
|
||||
|
||||
m_switch = ioport(ACTIVE_TAG)->read();
|
||||
m_active = ioport(ACTIVE_TAG)->read();
|
||||
|
||||
m_isrom0 = false;
|
||||
m_isrom12 = false;
|
||||
m_isgrom = false;
|
||||
m_address = 0;
|
||||
}
|
||||
|
||||
void ti_pcode_card_device::device_config_complete()
|
||||
@ -274,28 +294,20 @@ void ti_pcode_card_device::device_config_complete()
|
||||
|
||||
INPUT_CHANGED_MEMBER( ti_pcode_card_device::switch_changed )
|
||||
{
|
||||
if (VERBOSE>7) LOG("ti_pcode_card_device: switch changed to %d\n", newval);
|
||||
m_switch = (newval != 0);
|
||||
if (TRACE_SWITCH) logerror("Switch changed to %d\n", newval);
|
||||
m_active = (newval != 0);
|
||||
}
|
||||
|
||||
|
||||
MACHINE_CONFIG_FRAGMENT( ti99_pcode )
|
||||
MCFG_GROM_ADD( PGROM0_TAG, pgrom0_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM1_TAG, pgrom1_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM2_TAG, pgrom2_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM3_TAG, pgrom3_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM4_TAG, pgrom4_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM5_TAG, pgrom5_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM6_TAG, pgrom6_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM7_TAG, pgrom7_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM0_TAG, 0, PCODE_GROM_TAG, 0x0000, WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM1_TAG, 1, PCODE_GROM_TAG, 0x2000, WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM2_TAG, 2, PCODE_GROM_TAG, 0x4000, WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM3_TAG, 3, PCODE_GROM_TAG, 0x6000, WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM4_TAG, 4, PCODE_GROM_TAG, 0x8000, WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM5_TAG, 5, PCODE_GROM_TAG, 0xa000, WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM6_TAG, 6, PCODE_GROM_TAG, 0xc000, WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MCFG_GROM_ADD( PGROM7_TAG, 7, PCODE_GROM_TAG, 0xe000, WRITELINE(ti_pcode_card_device, ready_line))
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
INPUT_PORTS_START( ti99_pcode )
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include "emu.h"
|
||||
#include "peribox.h"
|
||||
#include "bus/ti99x/grom.h"
|
||||
#include "machine/tmc0430.h"
|
||||
|
||||
extern const device_type TI99_P_CODE;
|
||||
|
||||
@ -29,6 +29,9 @@ public:
|
||||
DECLARE_WRITE8_MEMBER(write) override;
|
||||
DECLARE_READ8Z_MEMBER(crureadz) override;
|
||||
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
||||
DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin) override;
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(clock_in) override;
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( ready_line );
|
||||
DECLARE_INPUT_CHANGED_MEMBER( switch_changed );
|
||||
@ -42,10 +45,22 @@ protected:
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
private:
|
||||
ti99_grom_device* m_grom[8];
|
||||
tmc0430_device* m_grom[8];
|
||||
UINT8* m_rom;
|
||||
int m_bank_select;
|
||||
bool m_switch;
|
||||
bool m_active;
|
||||
int m_clock_count;
|
||||
bool m_clockhigh;
|
||||
|
||||
// Address in card area
|
||||
bool m_inDsrArea;
|
||||
|
||||
bool m_isrom0;
|
||||
bool m_isrom12;
|
||||
bool m_isgrom;
|
||||
|
||||
// Recent address
|
||||
int m_address;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -259,7 +259,7 @@ WRITE8_MEMBER(peribox_device::write)
|
||||
SETADDRESS_DBIN_MEMBER(peribox_device::setaddress_dbin)
|
||||
{
|
||||
// Ignore the address when the TI-99/8 transmits the high-order 8 bits
|
||||
// if (!m_memen) return;
|
||||
if (!m_memen) return;
|
||||
|
||||
for (int i=2; i <= 8; i++)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,113 +18,368 @@
|
||||
|
||||
#include "emu.h"
|
||||
#include "ti99defs.h"
|
||||
#include "machine/tmc0430.h"
|
||||
#include "video/tms9928a.h"
|
||||
#include "sound/sn76496.h"
|
||||
#include "sound/tms5220.h"
|
||||
#include "gromport.h"
|
||||
#include "bus/ti99_peb/peribox.h"
|
||||
|
||||
extern const device_type MAINBOARD8;
|
||||
extern const device_type OSO;
|
||||
extern const device_type SPEECH8;
|
||||
|
||||
#define VAQUERRO_TAG "vaquerro"
|
||||
#define MOFETTA_TAG "mofetta"
|
||||
#define AMIGO_TAG "amigo"
|
||||
#define OSO_TAG "oso"
|
||||
#define SPEECHSYN_TAG "speechsyn"
|
||||
|
||||
#define NATIVE 0
|
||||
#define TI99EM 1
|
||||
#define PATGEN 2
|
||||
#define PHYSIC 3
|
||||
#define CONT 0
|
||||
#define STOP 1
|
||||
|
||||
#define SRAMNAME "SRAM"
|
||||
#define ROM0NAME "ROM0"
|
||||
#define ROM1A0NAME "ROM1A"
|
||||
#define ROM1C0NAME "ROM1C"
|
||||
#define INTSNAME "INTS"
|
||||
#define DRAMNAME "DRAM"
|
||||
#define PCODENAME "PCODE"
|
||||
|
||||
#define SRAM_SIZE 2048
|
||||
#define DRAM_SIZE 65536
|
||||
|
||||
// We use these constants in the read/write functions.
|
||||
enum mapper8_device_kind
|
||||
class mainboard8_device;
|
||||
extern const device_type VAQUERRO;
|
||||
extern const device_type MOFETTA;
|
||||
extern const device_type AMIGO;
|
||||
extern const device_type OSO;
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
MAP8_UNDEF = 0,
|
||||
MAP8_SRAM,
|
||||
MAP8_ROM0,
|
||||
MAP8_ROM1A0,
|
||||
MAP8_ROM1C0,
|
||||
MAP8_DRAM,
|
||||
MAP8_PCODE,
|
||||
MAP8_INTS,
|
||||
MAP8_DEV // device by name
|
||||
};
|
||||
|
||||
struct mapper8_list_entry
|
||||
{
|
||||
const char* name; // Name of the device (used for looking up the device)
|
||||
int mode; // Mode of the system which applies to this entry
|
||||
int stop; // Mapper shall stop searching for a matching device when this entry applies
|
||||
UINT32 select_pattern; // State of the address line bits when addressing this device
|
||||
UINT32 address_mask; // Bits of the address bus used to address this device
|
||||
UINT32 write_select; // Additional bits set when doing write accesses to this device
|
||||
};
|
||||
|
||||
#define MAPPER8_CONFIG(name) \
|
||||
const mapper8_config(name) =
|
||||
|
||||
#define MCFG_MAINBOARD8_READY_CALLBACK(_write) \
|
||||
devcb = &mainboard8_device::set_ready_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
struct mapper8_config
|
||||
{
|
||||
const mapper8_list_entry *devlist;
|
||||
SGMSEL = 1,
|
||||
TSGSEL = 2,
|
||||
P8GSEL = 4,
|
||||
P3GSEL = 8,
|
||||
VIDSEL = 16
|
||||
};
|
||||
|
||||
/*
|
||||
Device list of the mapper.
|
||||
Wait state generator (part of Vaquerro)
|
||||
*/
|
||||
class logically_addressed_device
|
||||
class waitstate_generator
|
||||
{
|
||||
friend class simple_list<logically_addressed_device>;
|
||||
friend class mainboard8_device;
|
||||
|
||||
public:
|
||||
logically_addressed_device(mapper8_device_kind kind, device_t *busdevice, const mapper8_list_entry &entry)
|
||||
: m_next(nullptr), m_kind(kind), m_device(busdevice), m_config(&entry) { };
|
||||
waitstate_generator() :
|
||||
m_counting(false),
|
||||
m_generate(false),
|
||||
m_counter(0),
|
||||
m_addressed(true),
|
||||
m_ready(true) { };
|
||||
void select_in(bool addressed);
|
||||
virtual void ready_in(line_state ready) =0;
|
||||
virtual void clock_in(line_state clkout) =0;
|
||||
void treset_in(line_state reset);
|
||||
|
||||
private:
|
||||
logically_addressed_device *m_next; // needed for simple_list
|
||||
mapper8_device_kind m_kind; // named device or predefined
|
||||
device_t *m_device; // the actual device
|
||||
const mapper8_list_entry *m_config;
|
||||
int select_out();
|
||||
void init(int select_value) { m_selvalue = select_value; }
|
||||
|
||||
line_state ready_out();
|
||||
|
||||
bool is_counting();
|
||||
bool is_generating();
|
||||
bool is_ready();
|
||||
|
||||
protected:
|
||||
// Two flipflops
|
||||
bool m_counting;
|
||||
bool m_generate;
|
||||
// Counter
|
||||
int m_counter;
|
||||
|
||||
// Select value (indicates selected line)
|
||||
int m_selvalue;
|
||||
|
||||
// Line state flags
|
||||
bool m_addressed;
|
||||
bool m_ready;
|
||||
};
|
||||
|
||||
class grom_waitstate_generator : public waitstate_generator
|
||||
{
|
||||
public:
|
||||
void ready_in(line_state ready) override;
|
||||
void clock_in(line_state clkout) override;
|
||||
};
|
||||
|
||||
class video_waitstate_generator : public waitstate_generator
|
||||
{
|
||||
public:
|
||||
void ready_in(line_state ready) override { };
|
||||
void clock_in(line_state clkout) override;
|
||||
};
|
||||
|
||||
/*
|
||||
Device list of the mapper.
|
||||
Custom chip: Vaquerro
|
||||
*/
|
||||
class physically_addressed_device
|
||||
class vaquerro_device : public device_t
|
||||
{
|
||||
friend class simple_list<physically_addressed_device>;
|
||||
friend class mainboard8_device;
|
||||
|
||||
public:
|
||||
physically_addressed_device(mapper8_device_kind kind, device_t *busdevice, const mapper8_list_entry &entry)
|
||||
: m_next(nullptr), m_kind(kind), m_device(busdevice), m_config(&entry) { };
|
||||
vaquerro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
void device_start() override;
|
||||
void device_reset() override;
|
||||
|
||||
line_state ready();
|
||||
void treset();
|
||||
|
||||
DECLARE_READ8_MEMBER( read );
|
||||
DECLARE_SETADDRESS_DBIN_MEMBER( set_address );
|
||||
|
||||
DECLARE_READ_LINE_MEMBER( sprd_out );
|
||||
DECLARE_READ_LINE_MEMBER( spwt_out );
|
||||
DECLARE_READ_LINE_MEMBER( sccs_out );
|
||||
DECLARE_READ_LINE_MEMBER( sromcs_out );
|
||||
|
||||
// Collective select line query
|
||||
int gromcs_out();
|
||||
|
||||
DECLARE_READ_LINE_MEMBER( vdprd_out );
|
||||
DECLARE_READ_LINE_MEMBER( vdpwt_out );
|
||||
DECLARE_READ_LINE_MEMBER( lascsq_out );
|
||||
DECLARE_READ_LINE_MEMBER( ggrdy_out );
|
||||
DECLARE_WRITE_LINE_MEMBER( hold_cpu );
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( crus_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( crusgl_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( clock_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( memen_in );
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( sgmry );
|
||||
DECLARE_WRITE_LINE_MEMBER( tsgry );
|
||||
DECLARE_WRITE_LINE_MEMBER( p8gry );
|
||||
DECLARE_WRITE_LINE_MEMBER( p3gry );
|
||||
|
||||
private:
|
||||
physically_addressed_device *m_next; // needed for simple_list
|
||||
mapper8_device_kind m_kind; // named device or predefined
|
||||
device_t *m_device; // the actual device
|
||||
const mapper8_list_entry *m_config;
|
||||
// Memory cycle state
|
||||
bool m_memen;
|
||||
|
||||
// Waiting for video
|
||||
bool m_video_wait;
|
||||
|
||||
// State of the CRUS line
|
||||
line_state m_crus;
|
||||
|
||||
// Are the GROM libraries turned on?
|
||||
bool m_crugl;
|
||||
|
||||
// Do we have a logical address space match?
|
||||
bool m_lasreq = false;
|
||||
|
||||
// Keep the decoding result (opens the SRY gate)
|
||||
bool m_grom_or_video = false;
|
||||
|
||||
// Select lines
|
||||
bool m_spwt;
|
||||
bool m_sccs;
|
||||
bool m_sromcs;
|
||||
bool m_sprd;
|
||||
bool m_vdprd;
|
||||
bool m_vdpwt;
|
||||
|
||||
// Collective GROM select state
|
||||
int m_gromsel;
|
||||
|
||||
// Outgoing READY
|
||||
line_state m_ggrdy;
|
||||
|
||||
// Outgoing READY latch (common flipflop driving SRY)
|
||||
bool m_sry;
|
||||
|
||||
// Holds the A14 address line state. We need this for the clock_in method.
|
||||
line_state m_a14;
|
||||
|
||||
// Keeps the recent DBIN level
|
||||
line_state m_dbin_level;
|
||||
|
||||
// Wait state logic components
|
||||
grom_waitstate_generator m_sgmws, m_tsgws, m_p8gws, m_p3gws;
|
||||
video_waitstate_generator m_vidws;
|
||||
|
||||
// Pointer to mainboard
|
||||
mainboard8_device* m_mainboard;
|
||||
};
|
||||
|
||||
/*
|
||||
Custom chip: Mofetta
|
||||
*/
|
||||
class mofetta_device : public device_t
|
||||
{
|
||||
public:
|
||||
mofetta_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
void device_start() override;
|
||||
void device_reset() override;
|
||||
|
||||
DECLARE_WRITE8_MEMBER( cruwrite );
|
||||
DECLARE_SETADDRESS_DBIN_MEMBER( set_address );
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( clock_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( msast_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( lascs_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( pmemen_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( skdrcs_in );
|
||||
|
||||
DECLARE_READ8_MEMBER( rom1cs_out );
|
||||
DECLARE_READ_LINE_MEMBER( gromclk_out );
|
||||
|
||||
DECLARE_READ_LINE_MEMBER( alccs_out );
|
||||
DECLARE_READ_LINE_MEMBER( prcs_out );
|
||||
DECLARE_READ_LINE_MEMBER( cmas_out );
|
||||
DECLARE_READ_LINE_MEMBER( dbc_out );
|
||||
|
||||
DECLARE_READ_LINE_MEMBER( rom1cs_out );
|
||||
DECLARE_READ_LINE_MEMBER( rom1am_out );
|
||||
DECLARE_READ_LINE_MEMBER( rom1al_out );
|
||||
|
||||
private:
|
||||
// Memory cycle state
|
||||
bool m_pmemen;
|
||||
|
||||
// Logical access
|
||||
bool m_lasreq;
|
||||
|
||||
// DRAM access
|
||||
bool m_skdrcs;
|
||||
|
||||
// Holds the decoding result; essentially names the selected line
|
||||
bool m_gromclk_up;
|
||||
|
||||
// Have we got the upper word of the address?
|
||||
bool m_gotfirstword;
|
||||
|
||||
// Address latch
|
||||
int m_address_latch;
|
||||
|
||||
// Most significant byte of the 24-bit address
|
||||
int m_prefix;
|
||||
|
||||
// CRU select of the 1700 device
|
||||
bool m_alcpg;
|
||||
|
||||
// CRU select of the 2700 device
|
||||
bool m_txspg;
|
||||
|
||||
// ROM1 select lines
|
||||
bool m_rom1cs;
|
||||
bool m_rom1am;
|
||||
bool m_rom1al;
|
||||
|
||||
// OSO select
|
||||
bool m_alccs;
|
||||
|
||||
// Pascal ROM select line
|
||||
bool m_prcs;
|
||||
|
||||
// Cartridge port select line
|
||||
bool m_cmas;
|
||||
|
||||
// GROM clock count (as frequency divider)
|
||||
int m_gromclock_count;
|
||||
|
||||
// Remember last msast state for edge detection
|
||||
line_state m_msast;
|
||||
|
||||
// Pointer to mainboard
|
||||
mainboard8_device* m_mainboard;
|
||||
};
|
||||
|
||||
/*
|
||||
Custom chip: Amigo
|
||||
*/
|
||||
class amigo_device : public device_t
|
||||
{
|
||||
public:
|
||||
amigo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
void device_start() override;
|
||||
void device_reset() override;
|
||||
|
||||
DECLARE_READ8_MEMBER( read );
|
||||
DECLARE_WRITE8_MEMBER( write );
|
||||
DECLARE_SETOFFSET_MEMBER( set_address );
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( srdy_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( clock_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( crus_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( lascs_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( memen_in );
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( holda_in );
|
||||
|
||||
DECLARE_READ_LINE_MEMBER( cpury_out );
|
||||
DECLARE_READ_LINE_MEMBER( sramcs_out );
|
||||
DECLARE_READ_LINE_MEMBER( skdrcs_out );
|
||||
|
||||
void connect_sram(UINT8* sram) { m_sram = sram; }
|
||||
bool mapper_accessed() { return m_mapper_accessed; }
|
||||
|
||||
private:
|
||||
// Memory cycle state
|
||||
bool m_memen;
|
||||
|
||||
// DMA methods for loading/saving maps
|
||||
void mapper_load();
|
||||
void mapper_save();
|
||||
|
||||
// Address mapper registers. Each offset is selected by the first 4 bits
|
||||
// of the logical address.
|
||||
UINT32 m_base_register[16];
|
||||
|
||||
// Indicates a logical space access
|
||||
bool m_logical_space;
|
||||
|
||||
// Physical address
|
||||
UINT32 m_physical_address;
|
||||
|
||||
// Pointer to SRAM where AMIGO needs to upload/download its map values
|
||||
UINT8* m_sram;
|
||||
|
||||
// Pointer to mainboard
|
||||
mainboard8_device* m_mainboard;
|
||||
|
||||
// Keep the system ready state
|
||||
line_state m_srdy;
|
||||
|
||||
// Outgoing READY level
|
||||
line_state m_ready_out;
|
||||
|
||||
// Keep the CRUS setting
|
||||
line_state m_crus;
|
||||
|
||||
// State of the address creation
|
||||
int m_amstate;
|
||||
|
||||
// Protection flags
|
||||
int m_protflag;
|
||||
|
||||
// Accessing SRAM
|
||||
bool m_sram_accessed;
|
||||
|
||||
// Accessing DRAM
|
||||
bool m_dram_accessed;
|
||||
|
||||
// Accessing the mapper
|
||||
bool m_mapper_accessed;
|
||||
|
||||
// Doing a DMA access
|
||||
bool m_sram_dma;
|
||||
|
||||
// HOLDA flag
|
||||
bool m_hold_acknowledged;
|
||||
|
||||
// Address in SRAM during DMA
|
||||
UINT32 m_sram_address;
|
||||
|
||||
// Number of the currently loaded/save base register
|
||||
int m_basereg;
|
||||
|
||||
// Latched value for mapper DMA transfer
|
||||
UINT32 m_mapvalue;
|
||||
};
|
||||
|
||||
/*
|
||||
Custom chip: OSO
|
||||
*/
|
||||
class ti998_oso_device : public device_t
|
||||
class oso_device : public device_t
|
||||
{
|
||||
public:
|
||||
ti998_oso_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
oso_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
DECLARE_READ8_MEMBER( read );
|
||||
DECLARE_WRITE8_MEMBER( write );
|
||||
void device_start() override;
|
||||
@ -136,73 +391,60 @@ private:
|
||||
UINT8 m_xmit;
|
||||
};
|
||||
|
||||
/*
|
||||
Speech support
|
||||
*/
|
||||
#define MCFG_SPEECH8_READY_CALLBACK(_write) \
|
||||
devcb = &ti998_spsyn_device::set_ready_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
class ti998_spsyn_device : public bus8z_device
|
||||
{
|
||||
public:
|
||||
ti998_spsyn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
template<class _Object> static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast<ti998_spsyn_device &>(device).m_ready.set_callback(object); }
|
||||
|
||||
DECLARE_READ8Z_MEMBER(readz) override;
|
||||
DECLARE_WRITE8_MEMBER(write) override;
|
||||
|
||||
DECLARE_READ8Z_MEMBER(crureadz) { };
|
||||
DECLARE_WRITE8_MEMBER(cruwrite) { };
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( speech8_ready );
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset(void) override;
|
||||
virtual const rom_entry *device_rom_region() const override;
|
||||
virtual machine_config_constructor device_mconfig_additions() const override;
|
||||
|
||||
private:
|
||||
tms5220_device *m_vsp;
|
||||
// UINT8 *m_speechrom; // pointer to speech ROM data
|
||||
// int m_load_pointer; // which 4-bit nibble will be affected by load address
|
||||
// int m_rombits_count; // current bit position in ROM
|
||||
// UINT32 m_sprom_address; // 18 bit pointer in ROM
|
||||
// UINT32 m_sprom_length; // length of data pointed by speechrom_data, from 0 to 2^18
|
||||
|
||||
// Ready line to the CPU
|
||||
devcb_write_line m_ready;
|
||||
};
|
||||
|
||||
#define MCFG_TISPEECH8_ADD(_tag, _conf) \
|
||||
MCFG_DEVICE_ADD(_tag, TI99_SPEECH8, 0) \
|
||||
MCFG_DEVICE_CONFIG(_conf)
|
||||
|
||||
|
||||
/*
|
||||
Main class
|
||||
*/
|
||||
class mainboard8_device : public bus8z_device
|
||||
class mainboard8_device : public device_t
|
||||
{
|
||||
public:
|
||||
mainboard8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
template<class _Object> static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast<mainboard8_device &>(device).m_ready.set_callback(object); }
|
||||
// Memory space
|
||||
DECLARE_READ8_MEMBER( read );
|
||||
DECLARE_WRITE8_MEMBER( write );
|
||||
DECLARE_SETOFFSET_MEMBER( setoffset );
|
||||
|
||||
DECLARE_READ8_MEMBER( readm); // used from address map
|
||||
DECLARE_WRITE8_MEMBER( writem ); // used from address map
|
||||
// I/O space
|
||||
DECLARE_READ8Z_MEMBER( crureadz );
|
||||
DECLARE_WRITE8_MEMBER( cruwrite );
|
||||
|
||||
DECLARE_READ8Z_MEMBER( readz ) override;
|
||||
DECLARE_WRITE8_MEMBER( write ) override;
|
||||
// Control lines
|
||||
DECLARE_WRITE_LINE_MEMBER( clock_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( dbin_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( msast_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( crus_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( ptgen_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( reset_console );
|
||||
DECLARE_WRITE_LINE_MEMBER( hold_cpu );
|
||||
DECLARE_WRITE_LINE_MEMBER( ggrdy_in );
|
||||
|
||||
DECLARE_READ8Z_MEMBER(crureadz);
|
||||
DECLARE_WRITE8_MEMBER(cruwrite);
|
||||
DECLARE_WRITE_LINE_MEMBER( holda_line );
|
||||
|
||||
void CRUS_set(bool state);
|
||||
void PTGE_set(bool state);
|
||||
template<class _Object> static devcb_base &set_ready_wr_callback(device_t &device, _Object object)
|
||||
{
|
||||
return downcast<mainboard8_device &>(device).m_ready.set_callback(object);
|
||||
}
|
||||
|
||||
void clock_in(int state);
|
||||
template<class _Object> static devcb_base &set_reset_wr_callback(device_t &device, _Object object)
|
||||
{
|
||||
return downcast<mainboard8_device &>(device).m_console_reset.set_callback(object);
|
||||
}
|
||||
|
||||
template<class _Object> static devcb_base &set_hold_wr_callback(device_t &device, _Object object)
|
||||
{
|
||||
return downcast<mainboard8_device &>(device).m_hold_line.set_callback(object);
|
||||
}
|
||||
|
||||
void set_paddress(int address);
|
||||
|
||||
// Ready lines from GROMs
|
||||
DECLARE_WRITE_LINE_MEMBER( system_grom_ready );
|
||||
DECLARE_WRITE_LINE_MEMBER( ptts_grom_ready );
|
||||
DECLARE_WRITE_LINE_MEMBER( p8_grom_ready );
|
||||
DECLARE_WRITE_LINE_MEMBER( p3_grom_ready );
|
||||
DECLARE_WRITE_LINE_MEMBER( sound_ready );
|
||||
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(void) override;
|
||||
@ -210,65 +452,115 @@ protected:
|
||||
machine_config_constructor device_mconfig_additions() const override;
|
||||
|
||||
private:
|
||||
bool access_logical_r(address_space& space, offs_t offset, UINT8 *value, UINT8 mem_mask );
|
||||
bool access_logical_w(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask );
|
||||
void access_physical_r(address_space& space, offs_t offset, UINT8 *value, UINT8 mem_mask );
|
||||
void access_physical_w(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask );
|
||||
void mapwrite(int offset, UINT8 data);
|
||||
// Propagates the end of the memory cycle
|
||||
void cycle_end();
|
||||
|
||||
// Original logical address.
|
||||
int m_logical_address;
|
||||
|
||||
// Mapped physical address.
|
||||
int m_physical_address;
|
||||
|
||||
// Hold the address space value so that we can use it in other methods.
|
||||
address_space* m_space;
|
||||
|
||||
// Indicates that a byte is waiting on the data bus (see m_latched_data)
|
||||
bool m_pending_write;
|
||||
|
||||
// Hold the value of the data bus. In a real machine, the data bus continues
|
||||
// to show that value, but in this emulation we have a push mechanism.
|
||||
UINT8 m_latched_data;
|
||||
|
||||
// Hold the level of the GROMCLK line
|
||||
int m_gromclk;
|
||||
|
||||
// Selecting GROM libraries
|
||||
void select_groms();
|
||||
|
||||
// Previous select state
|
||||
int m_prev_grom;
|
||||
|
||||
// Ready states
|
||||
bool m_speech_ready;
|
||||
bool m_sound_ready;
|
||||
bool m_pbox_ready;
|
||||
|
||||
// Holds the A14 address line state. We need this for the clock_in method.
|
||||
bool m_A14_set;
|
||||
|
||||
// 99/4A compatibility mode. Name is taken from the spec. If asserted, 99/4A compatibility is active.
|
||||
line_state m_crus;
|
||||
|
||||
// P-Code mode, negative logic. Name is taken from the spec. If asserted, P-Code libraries are available.
|
||||
// May be read as "Pascal and Text-to-speech GROM libraries ENable"
|
||||
line_state m_ptgen;
|
||||
|
||||
// Keeps the recent DBIN level
|
||||
line_state m_dbin_level;
|
||||
|
||||
// Ready line to the CPU
|
||||
devcb_write_line m_ready;
|
||||
|
||||
// All devices that are attached to the 16-bit address bus.
|
||||
simple_list<logically_addressed_device> m_logcomp;
|
||||
// Reset line to the main system
|
||||
devcb_write_line m_console_reset;
|
||||
|
||||
// All devices that are attached to the 24-bit mapped address bus.
|
||||
simple_list<physically_addressed_device> m_physcomp;
|
||||
|
||||
// Select bit for the internal DSR.
|
||||
bool m_dsr_selected;
|
||||
|
||||
// Select bit for the Hexbus DSR.
|
||||
bool m_hexbus_selected;
|
||||
|
||||
// 99/4A compatibility mode. Name is taken from the spec. If 1, 99/4A compatibility is active.
|
||||
bool m_CRUS;
|
||||
|
||||
// P-Code mode. Name is taken from the spec. If 0, P-Code libraries are available.
|
||||
// May be read as "Pascal and Text-to-speech GROM libraries Enable (Negative)"
|
||||
// Note: this is negative logic. GROMs are present only for PTGEN=0
|
||||
// We use PTGE as the inverse signal.
|
||||
bool m_PTGE;
|
||||
|
||||
// Counter for the wait states.
|
||||
int m_waitcount;
|
||||
|
||||
// Address mapper registers. Each offset is selected by the first 4 bits
|
||||
// of the logical address.
|
||||
UINT32 m_pas_offset[16];
|
||||
|
||||
// SRAM area of the system. Directly connected to the address decoder.
|
||||
UINT8 *m_sram;
|
||||
|
||||
// DRAM area of the system. Connected to the mapped address bus.
|
||||
UINT8 *m_dram;
|
||||
|
||||
// ROM area of the system. Directly connected to the logical address decoder.
|
||||
UINT8 *m_rom0;
|
||||
|
||||
// ROM area of the system. Directly connected to the physical address decoder.
|
||||
UINT8 *m_rom1;
|
||||
|
||||
// P-Code ROM area of the system. Directly connected to the physical address decoder.
|
||||
UINT8 *m_pcode;
|
||||
// Hold line to the main system
|
||||
devcb_write_line m_hold_line;
|
||||
|
||||
// Custom chips
|
||||
required_device<ti998_oso_device> m_oso;
|
||||
required_device<vaquerro_device> m_vaquerro;
|
||||
required_device<mofetta_device> m_mofetta;
|
||||
required_device<amigo_device> m_amigo;
|
||||
required_device<oso_device> m_oso;
|
||||
|
||||
// Debugging
|
||||
line_state m_last_ready;
|
||||
|
||||
// Video processor
|
||||
tms9118_device* m_video;
|
||||
|
||||
// Sound generator
|
||||
sn76496_base_device* m_sound;
|
||||
|
||||
// Speech processor
|
||||
cd2501ecd_device* m_speech;
|
||||
|
||||
// System GROM library
|
||||
tmc0430_device* m_sgrom[3];
|
||||
|
||||
// Text-to-speech GROM library
|
||||
tmc0430_device* m_tsgrom[8];
|
||||
|
||||
// Pascal 8 GROM library
|
||||
tmc0430_device* m_p8grom[8];
|
||||
|
||||
// Pascal 3 GROM library
|
||||
tmc0430_device* m_p3grom[3];
|
||||
|
||||
// Gromport (cartridge port)
|
||||
gromport_device* m_gromport;
|
||||
|
||||
// Peripheral box
|
||||
peribox_device* m_peb;
|
||||
|
||||
// Memory
|
||||
std::unique_ptr<UINT8[]> m_sram;
|
||||
std::unique_ptr<UINT8[]> m_dram;
|
||||
|
||||
// ROM area of the system.
|
||||
UINT8* m_rom0;
|
||||
UINT8* m_rom1;
|
||||
UINT8* m_pascalrom;
|
||||
};
|
||||
|
||||
#define MCFG_MAINBOARD8_READY_CALLBACK(_write) \
|
||||
devcb = &mainboard8_device::set_ready_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MAINBOARD8_RESET_CALLBACK(_write) \
|
||||
devcb = &mainboard8_device::set_reset_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MAINBOARD8_HOLD_CALLBACK(_write) \
|
||||
devcb = &mainboard8_device::set_hold_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
#define MCFG_MAINBOARD8_ADD(_tag, _devices) \
|
||||
MCFG_DEVICE_ADD(_tag, MAINBOARD8, 0) \
|
||||
MCFG_DEVICE_CONFIG( _devices )
|
||||
|
||||
#endif
|
||||
|
@ -75,9 +75,20 @@
|
||||
Constructor
|
||||
*/
|
||||
ti99_datamux_device::ti99_datamux_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, DATAMUX, "Databus multiplexer", tag, owner, clock, "ti99_datamux", __FILE__), m_spacep(nullptr),
|
||||
m_ready(*this), m_muxready(), m_sysready(), m_addr_buf(0), m_read_mode(false), m_latch(0), m_waitcount(0), m_ram16b(nullptr), m_use32k(false), m_base32k(0), m_cpu(nullptr)
|
||||
{ }
|
||||
: device_t(mconfig, DATAMUX, "Databus multiplexer", tag, owner, clock, "ti99_datamux", __FILE__),
|
||||
m_spacep(nullptr),
|
||||
m_ready(*this),
|
||||
m_addr_buf(0),
|
||||
m_dbin(CLEAR_LINE),
|
||||
m_muxready(CLEAR_LINE),
|
||||
m_sysready(CLEAR_LINE),
|
||||
m_latch(0),
|
||||
m_waitcount(0),
|
||||
m_ram16b(nullptr),
|
||||
m_use32k(false),
|
||||
m_base32k(0),
|
||||
m_console_groms_present(false)
|
||||
{ }
|
||||
|
||||
#define TRACE_READY 0
|
||||
#define TRACE_ACCESS 0
|
||||
@ -89,140 +100,236 @@ ti99_datamux_device::ti99_datamux_device(const machine_config &mconfig, const ch
|
||||
DEVICE ACCESSOR FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
void ti99_datamux_device::read_all(address_space& space, UINT16 addr, UINT8 *target)
|
||||
void ti99_datamux_device::read_all(address_space& space, UINT16 addr, UINT8 *value)
|
||||
{
|
||||
attached_device *dev = m_devices.first();
|
||||
// Valid access
|
||||
bool validaccess = ((addr & 0x0400)==0);
|
||||
|
||||
// Reading the odd address first (addr+1)
|
||||
while (dev != nullptr)
|
||||
if (validaccess)
|
||||
{
|
||||
if (dev->m_config->write_select != 0xffff) // write-only
|
||||
// GROM access
|
||||
if ((addr & 0xf801)==0x9800)
|
||||
{
|
||||
if ((addr & dev->m_config->address_mask)==dev->m_config->select)
|
||||
if (m_console_groms_present)
|
||||
{
|
||||
// Cast to the bus8z_device (see ti99defs.h)
|
||||
bus8z_device *devz = static_cast<bus8z_device *>(dev->m_device);
|
||||
devz->readz(space, addr, target);
|
||||
for (int i=0; i < 3; i++)
|
||||
{
|
||||
m_grom[i]->readz(space, addr, value);
|
||||
}
|
||||
}
|
||||
// hope we don't have two devices answering...
|
||||
// consider something like a logical OR and maybe some artificial smoke
|
||||
// GROMport (GROMs)
|
||||
m_gromport->readz(space, addr, value);
|
||||
}
|
||||
dev = dev->m_next;
|
||||
|
||||
// Video
|
||||
if ((addr & 0xf801)==0x8800) m_video->readz(space, addr, value);
|
||||
}
|
||||
|
||||
// GROMport (ROMs)
|
||||
if ((addr & 0xe000)==0x6000) m_gromport->readz(space, addr, value);
|
||||
|
||||
// PEB gets all accesses
|
||||
m_peb->readz(space, addr, value);
|
||||
m_peb->memen_in(CLEAR_LINE);
|
||||
}
|
||||
|
||||
void ti99_datamux_device::write_all(address_space& space, UINT16 addr, UINT8 value)
|
||||
{
|
||||
attached_device *dev = m_devices.first();
|
||||
while (dev != nullptr)
|
||||
// GROM access
|
||||
if ((addr & 0xf801)==0x9800)
|
||||
{
|
||||
if ((addr & dev->m_config->address_mask)==(dev->m_config->select | dev->m_config->write_select))
|
||||
if (m_console_groms_present)
|
||||
{
|
||||
bus8z_device *devz = static_cast<bus8z_device *>(dev->m_device);
|
||||
devz->write(space, addr, value);
|
||||
for (int i=0; i < 3; i++)
|
||||
m_grom[i]->write(space, addr, value);
|
||||
}
|
||||
dev = dev->m_next;
|
||||
// GROMport
|
||||
m_gromport->write(space, addr, value);
|
||||
}
|
||||
|
||||
// Other devices
|
||||
if ((addr & 0xe000)==0x6000) m_gromport->write(space, addr, value);
|
||||
if ((addr & 0xfc01)==0x8400) m_sound->write(space, addr, value);
|
||||
if ((addr & 0xf801)==0x8800) m_video->write(space, addr, value);
|
||||
|
||||
// PEB gets all accesses
|
||||
m_peb->write(space, addr, value);
|
||||
m_peb->memen_in(CLEAR_LINE);
|
||||
}
|
||||
|
||||
void ti99_datamux_device::setaddress_all(address_space& space, UINT16 addr)
|
||||
{
|
||||
attached_device *dev = m_devices.first();
|
||||
while (dev != nullptr)
|
||||
line_state a14 = ((addr & 2)!=0)? ASSERT_LINE : CLEAR_LINE;
|
||||
|
||||
// Valid access = not(DBIN and A5)
|
||||
bool validaccess = (m_dbin==CLEAR_LINE || (addr & 0x0400)==0);
|
||||
|
||||
// GROM access
|
||||
bool isgrom = ((addr & 0xf801)==0x9800) && validaccess;
|
||||
|
||||
// Cartridge ROM
|
||||
bool iscartrom = ((addr & 0xe000)==0x6000);
|
||||
|
||||
// Always deliver to GROM so that the select line may be cleared
|
||||
int lines = (m_dbin==ASSERT_LINE)? 1 : 0;
|
||||
if (a14==ASSERT_LINE) lines |= 2;
|
||||
line_state select = isgrom? ASSERT_LINE : CLEAR_LINE;
|
||||
|
||||
if (m_console_groms_present)
|
||||
for (int i=0; i < 3; i++)
|
||||
m_grom[i]->set_lines(space, lines, select);
|
||||
|
||||
// GROMport (GROMs)
|
||||
m_gromport->set_gromlines(space, lines, select);
|
||||
|
||||
if (validaccess)
|
||||
{
|
||||
if ((addr & dev->m_config->address_mask)==(dev->m_config->select | dev->m_config->write_select))
|
||||
{
|
||||
bus8z_device *devz = static_cast<bus8z_device *>(dev->m_device);
|
||||
devz->setaddress_dbin(space, addr, m_read_mode? ASSERT_LINE : CLEAR_LINE);
|
||||
}
|
||||
dev = dev->m_next;
|
||||
// Other devices
|
||||
if ((addr & 0xfc01)==0x8400) m_sound->setaddress_dbin(space, addr, m_dbin);
|
||||
if ((addr & 0xf801)==0x8800) m_video->setaddress_dbin(space, addr, m_dbin);
|
||||
}
|
||||
|
||||
// GROMport (ROMs)
|
||||
m_gromport->romgq_line(iscartrom? ASSERT_LINE : CLEAR_LINE);
|
||||
|
||||
// PEB gets all accesses
|
||||
m_peb->memen_in(ASSERT_LINE);
|
||||
m_peb->setaddress_dbin(space, addr, m_dbin);
|
||||
}
|
||||
|
||||
/*
|
||||
Special debugger access; these routines have no influence on the wait
|
||||
state generation.
|
||||
Special debugger access. The access is similar to the normal access,
|
||||
but it bypasses the wait state circuitry. Also, access ports of memory-
|
||||
mapped devices are excluded because their state would be changed
|
||||
unpredictably by the debugger access.
|
||||
*/
|
||||
UINT16 ti99_datamux_device::debugger_read(address_space& space, UINT16 addr)
|
||||
{
|
||||
UINT16 base32k = 0;
|
||||
UINT8 lval, hval;
|
||||
|
||||
UINT16 addrb = addr << 1;
|
||||
if (m_use32k)
|
||||
{
|
||||
if ((addrb & 0xe000)==0x2000) base32k = 0x1000;
|
||||
if (((addrb & 0xe000)==0xa000) || ((addrb & 0xc000)==0xc000)) base32k = 0x4000;
|
||||
}
|
||||
if (base32k != 0)
|
||||
{
|
||||
return m_ram16b[addr - base32k];
|
||||
}
|
||||
UINT16 value = 0;
|
||||
|
||||
if ((addrb & 0xe000)==0x0000) value = m_consolerom[(addrb & 0x1fff)>>1];
|
||||
else
|
||||
{
|
||||
lval = hval = 0;
|
||||
read_all(space, addrb+1, &lval);
|
||||
read_all(space, addrb, &hval);
|
||||
return ((hval << 8)&0xff00) | (lval & 0xff);
|
||||
if ((addrb & 0xfc00)==0x8000) value = m_padram[(addrb & 0x00ff)>>1];
|
||||
else
|
||||
{
|
||||
int base32k = 0;
|
||||
if (m_use32k)
|
||||
{
|
||||
if ((addrb & 0xe000)==0x2000) base32k = 0x2000;
|
||||
if (((addrb & 0xe000)==0xa000) || ((addrb & 0xc000)==0xc000)) base32k = 0x8000;
|
||||
}
|
||||
|
||||
if (base32k != 0) value = m_ram16b[(addrb-base32k)>>1];
|
||||
else
|
||||
{
|
||||
UINT8 lval = 0;
|
||||
UINT8 hval = 0;
|
||||
|
||||
if ((addr & 0xe000)==0x6000)
|
||||
{
|
||||
m_gromport->readz(space, addrb+1, &lval);
|
||||
m_gromport->readz(space, addrb, &hval);
|
||||
}
|
||||
m_peb->memen_in(ASSERT_LINE);
|
||||
m_peb->readz(space, addrb+1, &lval);
|
||||
m_peb->readz(space, addrb, &hval);
|
||||
m_peb->memen_in(CLEAR_LINE);
|
||||
value = ((hval << 8)&0xff00) | (lval & 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void ti99_datamux_device::debugger_write(address_space& space, UINT16 addr, UINT16 data)
|
||||
{
|
||||
UINT16 base32k = 0;
|
||||
|
||||
UINT16 addrb = addr << 1;
|
||||
if (m_use32k)
|
||||
{
|
||||
if ((addrb & 0xe000)==0x2000) base32k = 0x1000;
|
||||
if (((addrb & 0xe000)==0xa000) || ((addrb & 0xc000)==0xc000)) base32k = 0x4000;
|
||||
}
|
||||
if (base32k != 0)
|
||||
{
|
||||
m_ram16b[addr - base32k] = data;
|
||||
}
|
||||
|
||||
if ((addrb & 0xe000)==0x0000) return;
|
||||
|
||||
if ((addrb & 0xfc00)==0x8000) m_padram[(addrb & 0x00ff)>>1] = data;
|
||||
else
|
||||
{
|
||||
write_all(space, addrb+1, data & 0xff);
|
||||
write_all(space, addrb, (data >> 8) & 0xff);
|
||||
int base32k = 0;
|
||||
if (m_use32k)
|
||||
{
|
||||
if ((addrb & 0xe000)==0x2000) base32k = 0x2000;
|
||||
if (((addrb & 0xe000)==0xa000) || ((addrb & 0xc000)==0xc000)) base32k = 0x8000;
|
||||
}
|
||||
|
||||
if (base32k != 0) m_ram16b[(addrb-base32k)>>1] = data;
|
||||
else
|
||||
{
|
||||
if ((addr & 0xe000)==0x6000)
|
||||
{
|
||||
m_gromport->write(space, addr+1, data & 0xff);
|
||||
m_gromport->write(space, addr, (data>>8) & 0xff);
|
||||
}
|
||||
|
||||
m_peb->memen_in(ASSERT_LINE);
|
||||
m_peb->write(space, addr+1, data & 0xff);
|
||||
m_peb->write(space, addr, (data>>8) & 0xff);
|
||||
m_peb->memen_in(CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Read access. We are using two loops because the delay between both
|
||||
accesses must not occur within the loop. So we have one access on the bus,
|
||||
a delay, and then the second access (each one with possibly many attached
|
||||
devices)
|
||||
a delay, and then the second access.
|
||||
|
||||
mem_mask is always ffff on TMS processors (cannot control bus width)
|
||||
*/
|
||||
READ16_MEMBER( ti99_datamux_device::read )
|
||||
{
|
||||
UINT16 value = 0;
|
||||
|
||||
// Care for debugger
|
||||
if (space.debugger_access())
|
||||
{
|
||||
return debugger_read(space, offset);
|
||||
}
|
||||
|
||||
// Looks ugly, but this is close to the real thing. If the 16bit
|
||||
// memory expansion is installed in the console, and the access hits its
|
||||
// space, just respond to the memory access and don't bother the
|
||||
// datamux in any way. In particular, do not make the datamux insert wait
|
||||
// states.
|
||||
|
||||
if (m_base32k != 0)
|
||||
// Addresses below 0x2000 are ROM (no wait states)
|
||||
if ((m_addr_buf & 0xe000)==0x0000)
|
||||
{
|
||||
UINT16 reply = m_ram16b[offset-m_base32k];
|
||||
return reply & mem_mask;
|
||||
value = m_consolerom[(m_addr_buf & 0x1fff)>>1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The byte from the odd address has already been read into the latch
|
||||
// Reading the even address now (addr)
|
||||
UINT8 hbyte = 0;
|
||||
read_all(space, m_addr_buf, &hbyte);
|
||||
if (TRACE_ACCESS) logerror("datamux: read even byte from address %04x -> %02x\n", m_addr_buf, hbyte);
|
||||
// Addresses from 8300-83ff (mirrors at 8000, 8100, 8200) are console RAM (no wait states)
|
||||
if ((m_addr_buf & 0xfc00)==0x8000)
|
||||
{
|
||||
value = m_padram[(m_addr_buf & 0x00ff)>>1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Looks ugly, but this is close to the real thing. If the 16bit
|
||||
// memory expansion is installed in the console, and the access hits its
|
||||
// space, just respond to the memory access and don't bother the
|
||||
// datamux in any way. In particular, do not make the datamux insert wait
|
||||
// states.
|
||||
|
||||
return ((hbyte<<8) | m_latch) & mem_mask;
|
||||
if (m_base32k != 0)
|
||||
{
|
||||
value = m_ram16b[(m_addr_buf-m_base32k)>>1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The byte from the odd address has already been read into the latch
|
||||
// Reading the even address now (addr)
|
||||
UINT8 hbyte = 0;
|
||||
read_all(space, m_addr_buf, &hbyte);
|
||||
if (TRACE_ACCESS) logerror("Read even byte from address %04x -> %02x\n", m_addr_buf, hbyte);
|
||||
|
||||
value = (hbyte<<8) | m_latch;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -230,21 +337,29 @@ READ16_MEMBER( ti99_datamux_device::read )
|
||||
*/
|
||||
WRITE16_MEMBER( ti99_datamux_device::write )
|
||||
{
|
||||
// Addresses below 0x2000 are ROM and should be handled in the address map
|
||||
// by the ROM entry, but as the write handler for ROM is not mapped, we end up
|
||||
// here when there are invalid accesses, and this will mess up everything.
|
||||
if (offset < 0x1000) return;
|
||||
|
||||
if (space.debugger_access())
|
||||
{
|
||||
debugger_write(space, offset, data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Addresses below 0x2000 are ROM
|
||||
if ((m_addr_buf & 0xe000)==0x0000)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Addresses from 8300-83ff (mirrors at 8000, 8100, 8200) are console RAM
|
||||
if ((m_addr_buf & 0xfc00)==0x8000)
|
||||
{
|
||||
m_padram[(m_addr_buf & 0x00ff)>>1] = data;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the internal 32K expansion
|
||||
if (m_base32k != 0)
|
||||
{
|
||||
m_ram16b[offset-m_base32k] = data;
|
||||
m_ram16b[(m_addr_buf-m_base32k)>>1] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -264,21 +379,34 @@ WRITE16_MEMBER( ti99_datamux_device::write )
|
||||
*/
|
||||
SETOFFSET_MEMBER( ti99_datamux_device::setoffset )
|
||||
{
|
||||
if (TRACE_ADDRESS) logerror("datamux: set address %04x\n", offset << 1);
|
||||
m_addr_buf = offset << 1;
|
||||
m_waitcount = 0;
|
||||
|
||||
if (TRACE_ADDRESS) logerror("set address %04x\n", m_addr_buf);
|
||||
|
||||
if ((m_addr_buf & 0xe000) == 0x0000)
|
||||
{
|
||||
return; // console ROM
|
||||
}
|
||||
|
||||
if ((m_addr_buf & 0xfc00) == 0x8000)
|
||||
{
|
||||
return; // console RAM
|
||||
}
|
||||
|
||||
// Initialize counter
|
||||
// 1 cycle for loading into the datamux
|
||||
// 2 subsequent wait states (LSB)
|
||||
// 2 subsequent wait states (MSB)
|
||||
// clock cycle 6 is the nominal follower of the last wait state
|
||||
m_waitcount = 5;
|
||||
m_addr_buf = offset << 1;
|
||||
m_spacep = &space;
|
||||
|
||||
m_base32k = 0;
|
||||
if (m_use32k)
|
||||
{
|
||||
if ((m_addr_buf & 0xe000)==0x2000) m_base32k = 0x1000;
|
||||
if (((m_addr_buf & 0xe000)==0xa000) || ((m_addr_buf & 0xc000)==0xc000)) m_base32k = 0x4000;
|
||||
if ((m_addr_buf & 0xe000)==0x2000) m_base32k = 0x2000;
|
||||
if (((m_addr_buf & 0xe000)==0xa000) || ((m_addr_buf & 0xc000)==0xc000)) m_base32k = 0x8000;
|
||||
}
|
||||
|
||||
// Suspend the CPU if not using the 32K
|
||||
@ -308,13 +436,13 @@ WRITE_LINE_MEMBER( ti99_datamux_device::clock_in )
|
||||
if (TRACE_READY) logerror("datamux: stalled due to external READY=0\n");
|
||||
return;
|
||||
}
|
||||
if (m_read_mode)
|
||||
|
||||
if (m_dbin==ASSERT_LINE)
|
||||
{
|
||||
// Reading
|
||||
if (state==ASSERT_LINE)
|
||||
{ // raising edge
|
||||
m_waitcount--;
|
||||
if (m_waitcount==0)
|
||||
if (--m_waitcount==0)
|
||||
{
|
||||
m_muxready = ASSERT_LINE;
|
||||
ready_join();
|
||||
@ -333,8 +461,7 @@ WRITE_LINE_MEMBER( ti99_datamux_device::clock_in )
|
||||
{
|
||||
if (state==ASSERT_LINE)
|
||||
{ // raising edge
|
||||
m_waitcount--;
|
||||
if (m_waitcount==0)
|
||||
if (--m_waitcount==0)
|
||||
{
|
||||
m_muxready = ASSERT_LINE;
|
||||
ready_join();
|
||||
@ -365,21 +492,31 @@ void ti99_datamux_device::ready_join()
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_datamux_device::dbin_in )
|
||||
{
|
||||
m_read_mode = (state==ASSERT_LINE);
|
||||
if (TRACE_ADDRESS) logerror("datamux: data bus in = %d\n", m_read_mode? 1:0 );
|
||||
m_dbin = (line_state)state;
|
||||
if (TRACE_ADDRESS) logerror("data bus in = %d\n", (m_dbin==ASSERT_LINE)? 1:0 );
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_datamux_device::ready_line )
|
||||
{
|
||||
if (TRACE_READY)
|
||||
{
|
||||
if (state != m_sysready) logerror("datamux: READY line from PBox = %d\n", state);
|
||||
if (state != m_sysready) logerror("READY line from PBox = %d\n", state);
|
||||
}
|
||||
m_sysready = (line_state)state;
|
||||
// Also propagate to CPU via driver
|
||||
ready_join();
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_datamux_device::gromclk_in )
|
||||
{
|
||||
// Propagate to the GROMs
|
||||
if (m_console_groms_present)
|
||||
{
|
||||
for (int i=0; i < 3; i++) m_grom[i]->gclock_in(state);
|
||||
}
|
||||
m_gromport->gclock_in(state);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
DEVICE LIFECYCLE FUNCTIONS
|
||||
***************************************************************************/
|
||||
@ -398,15 +535,9 @@ void ti99_datamux_device::device_stop(void)
|
||||
|
||||
void ti99_datamux_device::device_reset(void)
|
||||
{
|
||||
const datamux_config *conf = reinterpret_cast<const datamux_config *>(static_config());
|
||||
|
||||
const dmux_device_list_entry *list = conf->devlist;
|
||||
|
||||
m_cpu = machine().device("maincpu");
|
||||
// m_space = &m_cpu->memory().space(AS_PROGRAM);
|
||||
|
||||
m_devices.reset(); // clear the list
|
||||
m_consolerom = (UINT16*)owner()->memregion(CONSOLEROM)->base();
|
||||
m_use32k = (ioport("RAM")->read()==1);
|
||||
m_console_groms_present = (ioport("GROMENA")->read()==1);
|
||||
|
||||
// better use a region?
|
||||
if (m_ram16b==nullptr)
|
||||
@ -414,51 +545,6 @@ void ti99_datamux_device::device_reset(void)
|
||||
m_ram16b = make_unique_clear<UINT16[]>(32768/2);
|
||||
}
|
||||
|
||||
// Now building the list of active devices at this databus multiplex.
|
||||
// We allow for turning off devices according to configuration switch settings.
|
||||
// In particular, the HSGPL card cannot function unless the console GROMs are
|
||||
// removed.
|
||||
if ( list != nullptr )
|
||||
{
|
||||
bool done = false;
|
||||
for (int i=0; !done; i++)
|
||||
{
|
||||
if (list[i].name == nullptr)
|
||||
{
|
||||
done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT32 set;
|
||||
bool active_device = true;
|
||||
if (list[i].setting!=nullptr)
|
||||
{
|
||||
set = ioport(list[i].setting)->read();
|
||||
active_device = ((set & list[i].set)==list[i].set) && ((set & list[i].unset)==0);
|
||||
}
|
||||
if (active_device)
|
||||
{
|
||||
device_t *dev = machine().device(list[i].name);
|
||||
if (dev != nullptr)
|
||||
{
|
||||
auto ad = new attached_device(dev, list[i]);
|
||||
m_devices.append(*ad);
|
||||
if (TRACE_SETUP) logerror("datamux: Device %s mounted at index %d.\n", list[i].name, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TRACE_SETUP) logerror("datamux: Device %s not found.\n", list[i].name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TRACE_SETUP) logerror("datamux: Device %s not mounted due to configuration setting %s.\n", list[i].name, list[i].setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TRACE_SETUP) logerror("datamux: Device count = %d\n", m_devices.count());
|
||||
|
||||
m_sysready = ASSERT_LINE;
|
||||
m_muxready = ASSERT_LINE;
|
||||
ready_join();
|
||||
@ -466,9 +552,22 @@ void ti99_datamux_device::device_reset(void)
|
||||
m_waitcount = 0;
|
||||
m_latch = 0;
|
||||
|
||||
m_read_mode = true;
|
||||
m_dbin = CLEAR_LINE;
|
||||
}
|
||||
|
||||
void ti99_datamux_device::device_config_complete()
|
||||
{
|
||||
m_video = downcast<bus8z_device*>(owner()->subdevice(VIDEO_SYSTEM_TAG));
|
||||
m_sound = downcast<ti_sound_sn94624_device*>(owner()->subdevice(TISOUND_TAG));
|
||||
m_gromport = downcast<gromport_device*>(owner()->subdevice(GROMPORT_TAG));
|
||||
m_peb = downcast<peribox_device*>(owner()->subdevice(PERIBOX_TAG));
|
||||
m_grom[0] = downcast<tmc0430_device*>(owner()->subdevice(GROM0_TAG));
|
||||
m_grom[1] = downcast<tmc0430_device*>(owner()->subdevice(GROM1_TAG));
|
||||
m_grom[2] = downcast<tmc0430_device*>(owner()->subdevice(GROM2_TAG));
|
||||
m_padram = make_unique_clear<UINT16[]>(256/2);
|
||||
}
|
||||
|
||||
|
||||
INPUT_PORTS_START( datamux )
|
||||
PORT_START( "RAM" ) /* config */
|
||||
PORT_CONFNAME( 0x01, 0x00, "Console 32 KiB RAM upgrade (16 bit)" )
|
||||
|
@ -15,53 +15,13 @@
|
||||
#define __DMUX__
|
||||
|
||||
#include "ti99defs.h"
|
||||
#include "videowrp.h"
|
||||
#include "machine/tmc0430.h"
|
||||
#include "gromport.h"
|
||||
#include "bus/ti99_peb/peribox.h"
|
||||
|
||||
extern const device_type DATAMUX;
|
||||
|
||||
/*
|
||||
Device that is attached to this datamux.
|
||||
The configuration setting is used for certain configurations
|
||||
where devices may only be used if others are turned off. In particular,
|
||||
if the HGSPL expansion card is used, the GROMs in the console must be
|
||||
removed.
|
||||
*/
|
||||
struct dmux_device_list_entry
|
||||
{
|
||||
const char *name; // Name of the device (used for looking up the device)
|
||||
UINT16 select; // State of the address line bits when addressing this device
|
||||
UINT16 address_mask; // Bits of the address bus used to address this device
|
||||
UINT16 write_select; // Bits set when doing write accesses to this device (ffff = write-only)
|
||||
const char *setting; // configuration switch that may have an effect for the presence of this device
|
||||
UINT8 set; // bits that must be set for this switch so that this device is present
|
||||
UINT8 unset; // bits that must be reset for this switch so that this device is present
|
||||
};
|
||||
|
||||
#define DMUX_CONFIG(name) \
|
||||
const datamux_config(name) =
|
||||
|
||||
struct datamux_config
|
||||
{
|
||||
const dmux_device_list_entry *devlist;
|
||||
};
|
||||
|
||||
/*
|
||||
Device list of this datamux.
|
||||
*/
|
||||
class attached_device
|
||||
{
|
||||
friend class simple_list<attached_device>;
|
||||
friend class ti99_datamux_device;
|
||||
|
||||
public:
|
||||
attached_device(device_t *busdevice, const dmux_device_list_entry &entry)
|
||||
: m_next(nullptr), m_device(busdevice), m_config(&entry) { };
|
||||
|
||||
private:
|
||||
attached_device *m_next;
|
||||
device_t *m_device; // the actual device
|
||||
const dmux_device_list_entry *m_config;
|
||||
};
|
||||
|
||||
/*
|
||||
Main class
|
||||
*/
|
||||
@ -77,6 +37,8 @@ public:
|
||||
DECLARE_WRITE_LINE_MEMBER( dbin_in );
|
||||
DECLARE_WRITE_LINE_MEMBER( ready_line );
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( gromclk_in );
|
||||
|
||||
template<class _Object> static devcb_base &static_set_ready_callback(device_t &device, _Object object)
|
||||
{
|
||||
return downcast<ti99_datamux_device &>(device).m_ready.set_callback(object);
|
||||
@ -87,9 +49,22 @@ protected:
|
||||
void device_start() override;
|
||||
void device_stop() override;
|
||||
void device_reset() override;
|
||||
void device_config_complete() override;
|
||||
ioport_constructor device_input_ports() const override;
|
||||
|
||||
private:
|
||||
// Link to the video processor
|
||||
bus8z_device* m_video;
|
||||
|
||||
// Link to the sound processor
|
||||
ti_sound_sn94624_device* m_sound;
|
||||
|
||||
// Link to the peripheral expansion box
|
||||
peribox_device* m_peb;
|
||||
|
||||
// Link to the cartridge port (aka GROM port)
|
||||
gromport_device* m_gromport;
|
||||
|
||||
// Keeps the address space pointer
|
||||
address_space* m_spacep;
|
||||
|
||||
@ -112,21 +87,18 @@ private:
|
||||
// Ready line to the CPU
|
||||
devcb_write_line m_ready;
|
||||
|
||||
// Address latch (emu). In reality, the address bus remains constant.
|
||||
UINT16 m_addr_buf;
|
||||
|
||||
// DBIN line
|
||||
line_state m_dbin;
|
||||
|
||||
// Own ready state.
|
||||
line_state m_muxready;
|
||||
|
||||
// Ready state. Needed to control wait state generation via inbound READY
|
||||
line_state m_sysready;
|
||||
|
||||
/* Address latch (emu). In reality, the address bus remains constant. */
|
||||
UINT16 m_addr_buf;
|
||||
|
||||
/* Stores the state of the DBIN line. */
|
||||
bool m_read_mode;
|
||||
|
||||
/* All devices that are attached to the 8-bit bus. */
|
||||
simple_list<attached_device> m_devices;
|
||||
|
||||
/* Latch which stores the first (odd) byte */
|
||||
UINT8 m_latch;
|
||||
|
||||
@ -136,22 +108,28 @@ private:
|
||||
/* Memory expansion (internal, 16 bit). */
|
||||
std::unique_ptr<UINT16[]> m_ram16b;
|
||||
|
||||
// Console RAM
|
||||
std::unique_ptr<UINT16[]> m_padram;
|
||||
|
||||
// Console ROM
|
||||
UINT16* m_consolerom;
|
||||
|
||||
// Console GROMs
|
||||
tmc0430_device* m_grom[3];
|
||||
|
||||
/* Use the memory expansion? */
|
||||
bool m_use32k;
|
||||
|
||||
/* Memory base for piggy-back 32K expansion. If 0, expansion is not used. */
|
||||
UINT16 m_base32k;
|
||||
|
||||
/* Reference to the CPU; avoid lookups. */
|
||||
device_t *m_cpu;
|
||||
// Console GROMs are available (the HSGPL expects them to be removed)
|
||||
bool m_console_groms_present;
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#define MCFG_DMUX_ADD(_tag, _devices) \
|
||||
MCFG_DEVICE_ADD(_tag, DATAMUX, 0) \
|
||||
MCFG_DEVICE_CONFIG( _devices )
|
||||
#endif
|
||||
|
||||
#define MCFG_DMUX_READY_HANDLER( _intcallb ) \
|
||||
devcb = &ti99_datamux_device::static_set_ready_callback( *device, DEVCB_##_intcallb );
|
||||
|
||||
#endif
|
||||
|
@ -535,6 +535,7 @@ READ8_MEMBER( geneve_mapper_device::readm )
|
||||
// 1001 0000 0000 0000
|
||||
// We need to add the address prefix bits
|
||||
m_peribox->readz(space, dec->offset, &value, 0xff);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
if (TRACE_READ) logerror("%s: Read speech -> %02x\n", tag(), value);
|
||||
break;
|
||||
|
||||
@ -594,6 +595,7 @@ READ8_MEMBER( geneve_mapper_device::readm )
|
||||
// 0x000000-0x1fffff for the GenMod.(AME,AMD,AMC,AMB,AMA,A0 ...,A15)
|
||||
|
||||
m_peribox->readz(space, dec->physaddr, &value, 0xff);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
if (TRACE_READ) logerror("%s: Read P-Box %04x (%06x) -> %02x\n", tag(), dec->offset, dec->physaddr, value);
|
||||
break;
|
||||
|
||||
@ -616,6 +618,7 @@ READ8_MEMBER( geneve_mapper_device::readm )
|
||||
case MPGMBOX:
|
||||
// Route everything else to the P-Box
|
||||
m_peribox->readz(space, dec->physaddr, &value, 0xff);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
@ -701,6 +704,7 @@ WRITE8_MEMBER( geneve_mapper_device::writem )
|
||||
// 1001 0100 0000 0000
|
||||
// We need to add the address prefix bits
|
||||
m_peribox->write(space, dec->offset, data, 0xff);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
if (TRACE_WRITE) logerror("%s: Write speech <- %02x\n", tag(), data);
|
||||
break;
|
||||
|
||||
@ -756,6 +760,7 @@ WRITE8_MEMBER( geneve_mapper_device::writem )
|
||||
dec->physaddr = (dec->physaddr & 0x0007ffff); // 19 bit address
|
||||
if (TRACE_WRITE) logerror("%s: Write P-Box %04x (%06x) <- %02x\n", tag(), offset, dec->physaddr, data);
|
||||
m_peribox->write(space, dec->physaddr, data, 0xff);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
break;
|
||||
|
||||
case MPGMDRAM:
|
||||
@ -775,6 +780,7 @@ WRITE8_MEMBER( geneve_mapper_device::writem )
|
||||
case MPGMBOX:
|
||||
// Route everything else to the P-Box
|
||||
m_peribox->write(space, dec->physaddr, data, 0xff);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -875,6 +881,7 @@ void geneve_mapper_device::decode(address_space& space, offs_t offset, bool read
|
||||
// We need to add the address prefix bits
|
||||
dec->function = MLTSPEECH;
|
||||
dec->offset = offset | ((m_genmod)? 0x170000 : 0x070000);
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
m_peribox->setaddress_dbin(space, dec->offset, read_mode);
|
||||
set_wait(1);
|
||||
return;
|
||||
@ -954,6 +961,7 @@ void geneve_mapper_device::decode(address_space& space, offs_t offset, bool read
|
||||
dec->function = MPGBOX;
|
||||
|
||||
dec->physaddr = (dec->physaddr & 0x0007ffff); // 19 bit address (with AMA..AMC)
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
m_peribox->setaddress_dbin(space, dec->physaddr, read_mode);
|
||||
return;
|
||||
}
|
||||
@ -986,6 +994,7 @@ void geneve_mapper_device::decode(address_space& space, offs_t offset, bool read
|
||||
// Check: Are waitstates completely turned off for turbo mode, or
|
||||
// merely the waitstates for DRAM memory access and box access?
|
||||
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
m_peribox->setaddress_dbin(space, dec->physaddr, read_mode);
|
||||
return;
|
||||
}
|
||||
@ -1072,6 +1081,7 @@ void geneve_mapper_device::decode(address_space& space, offs_t offset, bool read
|
||||
{
|
||||
dec->function = MLTSPEECH;
|
||||
dec->offset = dec->offset | ((m_genmod)? 0x170000 : 0x070000);
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
m_peribox->setaddress_dbin(space, dec->offset, read_mode);
|
||||
set_wait(1);
|
||||
return;
|
||||
@ -1151,6 +1161,7 @@ void geneve_mapper_device::decode(address_space& space, offs_t offset, bool read
|
||||
// only AMA, AMB, AMC are used; AMD and AME are not used
|
||||
dec->function = MPGBOX;
|
||||
dec->physaddr = (dec->physaddr & 0x0007ffff); // 19 bit address
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
m_peribox->setaddress_dbin(space, dec->physaddr, read_mode);
|
||||
set_wait(1);
|
||||
}
|
||||
@ -1175,6 +1186,7 @@ void geneve_mapper_device::decode(address_space& space, offs_t offset, bool read
|
||||
// Route everything else to the P-Box
|
||||
dec->function = MPGMBOX;
|
||||
dec->physaddr = (dec->physaddr & 0x001fffff); // 21 bit address for Genmod
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
m_peribox->setaddress_dbin(space, dec->physaddr, read_mode);
|
||||
if (!m_turbo) set_wait(1);
|
||||
}
|
||||
@ -1346,7 +1358,7 @@ WRITE_LINE_MEMBER( geneve_mapper_device::pfm_output_enable )
|
||||
void geneve_mapper_device::device_start()
|
||||
{
|
||||
// Get pointers
|
||||
m_peribox = machine().device<bus8z_device>(PERIBOX_TAG);
|
||||
m_peribox = machine().device<peribox_device>(PERIBOX_TAG);
|
||||
m_keyboard = machine().device<geneve_keyboard_device>(GKEYBOARD_TAG);
|
||||
m_video = machine().device<bus8z_device>(VIDEO_SYSTEM_TAG);
|
||||
m_sound = machine().device<bus8z_device>(TISOUND_TAG);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "video/v9938.h"
|
||||
#include "cpu/tms9900/tms9995.h"
|
||||
#include "machine/at29x.h"
|
||||
#include "bus/ti99_peb/peribox.h"
|
||||
|
||||
extern const device_type GENEVE_MOUSE;
|
||||
extern const device_type GENEVE_KEYBOARD;
|
||||
@ -207,7 +208,7 @@ private:
|
||||
|
||||
geneve_keyboard_device* m_keyboard;
|
||||
bus8z_device* m_video;
|
||||
bus8z_device* m_peribox;
|
||||
peribox_device* m_peribox;
|
||||
bus8z_device* m_sound;
|
||||
UINT8* m_eprom;
|
||||
UINT8* m_sram;
|
||||
|
@ -1,269 +0,0 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Michael Zapf
|
||||
/***************************************************************************
|
||||
|
||||
GROM emulation (aka TMC0430)
|
||||
|
||||
+----+--+----+
|
||||
AD7 |1 G 16| Vss
|
||||
AD6 |2 R 15| GR
|
||||
AD5 |3 O 14| Vdd
|
||||
AD4 |4 M 13| GRC
|
||||
AD3 |5 12| M
|
||||
AD2 |6 11| MO
|
||||
AD1 |7 10| GS*
|
||||
AD0 |8 9| Vcc
|
||||
+------------+
|
||||
|
||||
GR = GROM Ready. Should be connected to processor's READY/HOLD*.
|
||||
GRC = GROM clock. Typically in the range of 400-500 kHz.
|
||||
M = Direction. 1=read, 0=write
|
||||
MO = Mode. 1=address counter access, 0=data access
|
||||
GS* = GROM select. 0=select, 1=deselect
|
||||
|
||||
GROMs are slow ROM devices, which are
|
||||
interfaced via a 8-bit data bus, and include an internal address pointer
|
||||
which is incremented after each read. This implies that accesses are
|
||||
faster when reading consecutive bytes, although the address pointer can be
|
||||
read and written at any time.
|
||||
|
||||
GROMs are generally used to store programs written in GPL (Graphic Programming
|
||||
Language): a proprietary, interpreted language. The GPL interpreter takes
|
||||
most space of the TI-99/4A system ROMs.
|
||||
|
||||
Both TI-99/4 and TI-99/4A include three GROMs, with some start-up code,
|
||||
system routines and TI-Basic. TI99/4 includes an additional Equation
|
||||
Editor. According to the preliminary schematics found on ftp.whtech.com,
|
||||
TI-99/8 includes the three standard GROMs and 16 GROMs for the UCSD
|
||||
p-system. TI99/2 does not include GROMs at all, and was not designed to
|
||||
support any, although it should be relatively easy to create an expansion
|
||||
card with the GPL interpreter and a /4a cartridge port.
|
||||
|
||||
Communication with GROM is done by writing and reading data over the
|
||||
AD0-AD7 lines. Within the TI-99 systems, the address bus is decoded for
|
||||
the M, GS*, and MO lines: Writing a byte to address 9c02 asserts the GS* and
|
||||
MO line, and clears the M line, which means the transmitted byte is put into
|
||||
the internal address register. Two bytes must be written to set up the
|
||||
complete address.
|
||||
|
||||
It was obviously planned to offer GRAM circuits as well, since the
|
||||
programming manuals refer to writing to a special address, clearing the MO
|
||||
line. Although the TI-99 systems reserve a port in the memory space, no one
|
||||
has ever seen a GRAM circuit in the wild. However, third-party products like
|
||||
HSGPL or GRAM Kracker simulate GRAMs using conventional RAM with some
|
||||
addressing circuitry, usually in a custom chip.
|
||||
|
||||
Each GROM is logically 8 KiB long. Original TI-built GROM are 6 KiB long;
|
||||
the extra 2kb can be read, and follow the following formula:
|
||||
|
||||
GROM[0x1800+offset] = GROM[0x0800+offset] | GROM[0x1000+offset];
|
||||
|
||||
(sounds like address decoding is incomplete - we are lucky we don't burn
|
||||
any silicon when doing so... Needless to say, some hackers simulated 8kb
|
||||
GRAMs and GROMs with normal RAM/PROM chips and glue logic.)
|
||||
|
||||
The address pointer is incremented after each GROM operation, but it will
|
||||
always remain within the bounds of the currently selected GROM (e.g. after
|
||||
0x3fff comes 0x2000).
|
||||
|
||||
Since address are 16-bit long, you can have up to 8 GROMs. Accordingly,
|
||||
a cartridge may include up to 5 GROMs.
|
||||
|
||||
Every GROM has an internal ID which represents the high-order three
|
||||
address bits. The address counter can be set to any value from 0
|
||||
to 0xffff; the GROM will only react when selected and when the current
|
||||
address counter's high-order bits match the ID of the chip.
|
||||
Example: When the ID is 6, the GROM will react when the address
|
||||
counter contains a value from 0xc000 to 0xdfff.
|
||||
|
||||
CHECK: Reading the address increases the counter only once. The first access
|
||||
returns the MSB, the second (and all following accesses) return the LSB.
|
||||
|
||||
Michael Zapf, August 2010
|
||||
January 2012: rewritten as class
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "grom.h"
|
||||
|
||||
#define TRACE_ADDRESS 0
|
||||
|
||||
/*
|
||||
Constructor.
|
||||
*/
|
||||
ti99_grom_device::ti99_grom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: bus8z_device(mconfig, GROM, "TI-99 GROM device", tag, owner, clock, "ti99_grom", __FILE__), m_writable(false), m_ident(0), m_size(0),
|
||||
m_gromready(*this), m_clockrate(0), m_address(0), m_buffer(0), m_raddr_LSB(false), m_waddr_LSB(false), m_memptr(nullptr), m_timer(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
Reading from the chip. Represents an access with M=1, GS*=0. The MO bit is
|
||||
defined by the offset (0 or 1). This is the enhanced read function with
|
||||
Z state.
|
||||
*/
|
||||
READ8Z_MEMBER( ti99_grom_device::readz )
|
||||
{
|
||||
// Prevent debugger access
|
||||
if (space.debugger_access()) return;
|
||||
|
||||
if (offset & 2)
|
||||
{
|
||||
// GROMs generally answer the address read request
|
||||
// (important if GROM simulators do not serve the request but rely on
|
||||
// the console GROMs) so we don't check the ident
|
||||
|
||||
/* When reading, reset the hi/lo flag byte for writing. */
|
||||
/* TODO: Verify this with a real machine. */
|
||||
m_waddr_LSB = false;
|
||||
|
||||
/* Address reading is done in two steps; first, the high byte */
|
||||
/* is transferred, then the low byte. */
|
||||
if (m_raddr_LSB)
|
||||
{
|
||||
/* second pass */
|
||||
*value = m_address & 0x00ff;
|
||||
m_raddr_LSB = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* first pass */
|
||||
*value = (m_address & 0xff00)>>8;
|
||||
m_raddr_LSB = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((m_address >> 13)&0x07)==m_ident)
|
||||
{
|
||||
// GROMs are buffered. Data is retrieved from a buffer,
|
||||
// while the buffer is replaced with the next cell content.
|
||||
if (TRACE_ADDRESS) if (m_ident==0) logerror("grom0: %04x = %02x\n", m_address-1, m_buffer);
|
||||
*value = m_buffer;
|
||||
// Get next value, put it in buffer. Note that the GROM
|
||||
// wraps at 8K boundaries.
|
||||
UINT16 addr = m_address-(m_ident<<13);
|
||||
|
||||
if (m_size == 0x1800 && ((m_address&0x1fff)>=0x1800))
|
||||
m_buffer = m_memptr[addr-0x1000] | m_memptr[addr-0x0800];
|
||||
else
|
||||
m_buffer = m_memptr[addr];
|
||||
}
|
||||
// Note that all GROMs update their address counter.
|
||||
// TODO: Check this on a real console
|
||||
m_address = (m_address & 0xE000) | ((m_address + 1)&0x1FFF);
|
||||
|
||||
// Reset the read and write address flipflops.
|
||||
m_raddr_LSB = m_waddr_LSB = false;
|
||||
|
||||
// Maybe the timer is also required for address reading/setting, but
|
||||
// we don't have such technical details on GROMs.
|
||||
clear_ready();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Writing to the chip. Represents an access with M=0, GS*=0. The MO bit is
|
||||
defined by the offset (0 or 1).
|
||||
*/
|
||||
WRITE8_MEMBER( ti99_grom_device::write )
|
||||
{
|
||||
// Prevent debugger access
|
||||
if (space.debugger_access()) return;
|
||||
|
||||
if (offset & 2)
|
||||
{
|
||||
/* write GROM address */
|
||||
/* see comments above */
|
||||
m_raddr_LSB = false;
|
||||
|
||||
/* Implements the internal flipflop. */
|
||||
/* The Editor/Assembler manuals says that the current address */
|
||||
/* plus one is returned. This effect is properly emulated */
|
||||
/* by using a read-ahead buffer. */
|
||||
if (m_waddr_LSB)
|
||||
{
|
||||
/* Accept low byte (2nd write) */
|
||||
m_address = (m_address & 0xFF00) | data;
|
||||
/* Setting the address causes a new prefetch */
|
||||
if (is_selected())
|
||||
{
|
||||
m_buffer = m_memptr[m_address-(m_ident<<13)];
|
||||
}
|
||||
m_waddr_LSB = false;
|
||||
if (TRACE_ADDRESS) if (m_ident==0) logerror("grom0: %04x\n", m_address);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Accept high byte (1st write). Do not advance the address conter. */
|
||||
m_address = (data << 8) | (m_address & 0xFF);
|
||||
m_waddr_LSB = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* write GRAM data */
|
||||
if ((((m_address >> 13)&0x07)==m_ident) && m_writable)
|
||||
{
|
||||
UINT16 write_addr;
|
||||
// We need to rewind by 1 because the read address has already advanced.
|
||||
// However, do not change the address counter!
|
||||
write_addr = (m_address & 0xE000) | ((m_address - 1)&0x1FFF);
|
||||
|
||||
// UINT16 addr = m_address-(m_ident<<13);
|
||||
if (m_size > 0x1800 || ((m_address&0x1fff)<0x1800))
|
||||
m_memptr[write_addr-(m_ident<<13)] = data;
|
||||
}
|
||||
m_raddr_LSB = m_waddr_LSB = false;
|
||||
clear_ready();
|
||||
}
|
||||
m_address = (m_address & 0xE000) | ((m_address + 1)&0x1FFF);
|
||||
}
|
||||
|
||||
/*
|
||||
Timing. We assume that each data read results in READY going down for
|
||||
one cycle at the given frequency.
|
||||
*/
|
||||
void ti99_grom_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
m_gromready(ASSERT_LINE);
|
||||
}
|
||||
|
||||
void ti99_grom_device::clear_ready()
|
||||
{
|
||||
m_gromready(CLEAR_LINE);
|
||||
m_timer->adjust(attotime::from_hz(m_clockrate));
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
DEVICE FUNCTIONS
|
||||
***************************************************************************/
|
||||
|
||||
void ti99_grom_device::device_start(void)
|
||||
{
|
||||
const ti99grom_config *conf = reinterpret_cast<const ti99grom_config *>(static_config());
|
||||
|
||||
m_memptr = owner()->memregion(conf->regionname)->base();
|
||||
assert (m_memptr!=nullptr);
|
||||
m_memptr += conf->offset_reg;
|
||||
|
||||
m_size = conf->size;
|
||||
m_clockrate = conf->clockrate;
|
||||
m_writable = conf->writable;
|
||||
m_ident = conf->ident;
|
||||
m_gromready.resolve_safe();
|
||||
|
||||
m_timer = timer_alloc(0);
|
||||
}
|
||||
|
||||
void ti99_grom_device::device_reset(void)
|
||||
{
|
||||
m_address = 0;
|
||||
m_raddr_LSB = false;
|
||||
m_waddr_LSB = false;
|
||||
m_buffer = 0;
|
||||
}
|
||||
|
||||
const device_type GROM = &device_creator<ti99_grom_device>;
|
@ -1,108 +0,0 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Michael Zapf
|
||||
/***************************************************************************
|
||||
|
||||
GROM emulation
|
||||
See grom.c for documentation,
|
||||
|
||||
Michael Zapf
|
||||
|
||||
February 2012: Rewritten as class
|
||||
|
||||
***************************************************************************/
|
||||
#ifndef __TI99GROM__
|
||||
#define __TI99GROM__
|
||||
|
||||
#include "ti99defs.h"
|
||||
|
||||
struct ti99grom_config
|
||||
{
|
||||
bool writable;
|
||||
int ident;
|
||||
const char *regionname;
|
||||
offs_t offset_reg;
|
||||
int size;
|
||||
int clockrate;
|
||||
};
|
||||
|
||||
#define GROM_CONFIG(name) \
|
||||
const ti99grom_config(name) =
|
||||
|
||||
#define MCFG_GROM_READY_CALLBACK(_write) \
|
||||
devcb = &ti99_grom_device::set_ready_wr_callback(*device, DEVCB_##_write);
|
||||
|
||||
extern const device_type GROM;
|
||||
|
||||
/*
|
||||
ti99_grom. For bus8z_device see ti99defs.h
|
||||
*/
|
||||
class ti99_grom_device : public bus8z_device, ti99grom_config
|
||||
{
|
||||
public:
|
||||
ti99_grom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
template<class _Object> static devcb_base &set_ready_wr_callback(device_t &device, _Object object) { return downcast<ti99_grom_device &>(device).m_gromready.set_callback(object); }
|
||||
|
||||
DECLARE_READ8Z_MEMBER(readz) override;
|
||||
DECLARE_WRITE8_MEMBER(write) override;
|
||||
|
||||
private:
|
||||
// Is this a GRAM (never seen actually, but obviously planned)
|
||||
bool m_writable;
|
||||
|
||||
// Identification of this GROM (0-7)
|
||||
int m_ident;
|
||||
|
||||
// If the GROM has only 6 KiB, the remaining 2 KiB are filled with a
|
||||
// specific byte pattern which is created by a logical OR of lower
|
||||
// regions
|
||||
int m_size;
|
||||
|
||||
// Ready callback. This line is usually connected to the READY pin of the CPU.
|
||||
devcb_write_line m_gromready;
|
||||
|
||||
// Frequency of the incoming GROM clock. In most application cases the
|
||||
// GROM gets its clock from the video display processor (TMS9918)
|
||||
int m_clockrate;
|
||||
|
||||
/* Address pointer. */
|
||||
// This value is always expected to be in the range 0x0000 - 0xffff, even
|
||||
// when this GROM is not addressed.
|
||||
UINT16 m_address;
|
||||
|
||||
/* GROM data buffer. */
|
||||
UINT8 m_buffer;
|
||||
|
||||
/* Internal flip-flop. Used when retrieving the address counter. */
|
||||
bool m_raddr_LSB;
|
||||
|
||||
/* Internal flip-flops. Used when writing the address counter.*/
|
||||
bool m_waddr_LSB;
|
||||
|
||||
/* Pointer to the memory region contained in this GROM. */
|
||||
UINT8 *m_memptr;
|
||||
|
||||
// Timer for READY line operation
|
||||
emu_timer *m_timer;
|
||||
|
||||
/* Indicates whether this device will react on the next read/write data access. */
|
||||
inline int is_selected()
|
||||
{
|
||||
return (((m_address >> 13)&0x07)==m_ident);
|
||||
}
|
||||
|
||||
// Calling this method causes the READY line to be cleared, which puts the
|
||||
// CPU into wait state mode. A timer is set to raise READY again.
|
||||
void clear_ready();
|
||||
|
||||
virtual void device_start(void) override;
|
||||
virtual void device_reset(void) override;
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
};
|
||||
|
||||
|
||||
#define MCFG_GROM_ADD(_tag, _config) \
|
||||
MCFG_DEVICE_ADD(_tag, GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config)
|
||||
|
||||
#endif
|
@ -40,7 +40,7 @@
|
||||
|
||||
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 grom.h).
|
||||
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
|
||||
@ -119,6 +119,7 @@
|
||||
#define TRACE_ILLWRITE 0
|
||||
#define TRACE_CONFIG 0
|
||||
#define TRACE_READ 0
|
||||
#define TRACE_WRITE 0
|
||||
#define TRACE_GROM 0
|
||||
#define TRACE_GKRACKER 0
|
||||
#define TRACE_CRU 0
|
||||
@ -186,20 +187,33 @@ gromport_device::gromport_device(const machine_config &mconfig, const char *tag,
|
||||
m_connector(nullptr),
|
||||
m_reset_on_insert(true),
|
||||
m_console_ready(*this),
|
||||
m_console_reset(*this), m_grombase(0), m_grommask(0)
|
||||
m_console_reset(*this) // , m_grombase(0), m_grommask(0)
|
||||
{ }
|
||||
|
||||
/* Only called for addresses 6000-7fff and GROM addresses (see datamux config) */
|
||||
/*
|
||||
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, value);
|
||||
{
|
||||
m_connector->readz(space, offset & m_mask, value);
|
||||
if (TRACE_READ) if (m_romgq) logerror("Read %04x -> %02x\n", offset, *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)
|
||||
m_connector->write(space, offset, data);
|
||||
{
|
||||
if (TRACE_WRITE) if (m_romgq) logerror("Write %04x <- %02x\n", offset, data);
|
||||
m_connector->write(space, offset & m_mask, data);
|
||||
}
|
||||
}
|
||||
|
||||
READ8Z_MEMBER(gromport_device::crureadz)
|
||||
@ -219,6 +233,31 @@ 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();
|
||||
@ -230,11 +269,11 @@ void gromport_device::device_reset()
|
||||
m_reset_on_insert = (ioport("CARTRESET")->read()==0x01);
|
||||
}
|
||||
|
||||
void gromport_device::set_grom_base(UINT16 grombase, UINT16 grommask)
|
||||
{
|
||||
m_grombase = grombase;
|
||||
m_grommask = grommask;
|
||||
}
|
||||
// void gromport_device::set_grom_base(UINT16 grombase, UINT16 grommask)
|
||||
// {
|
||||
// m_grombase = grombase;
|
||||
// m_grommask = grommask;
|
||||
// }
|
||||
|
||||
/*
|
||||
Shall we reset the console when a cartridge has been inserted?
|
||||
@ -255,15 +294,18 @@ void gromport_device::cartridge_inserted()
|
||||
void gromport_device::device_config_complete()
|
||||
{
|
||||
m_connector = static_cast<ti99_cartridge_connector_device*>(subdevices().first());
|
||||
set_grom_base(0x9800, 0xf800);
|
||||
}
|
||||
|
||||
SLOT_INTERFACE_START( gromport )
|
||||
SLOT_INTERFACE_START( gromport4 )
|
||||
SLOT_INTERFACE("single", GROMPORT_SINGLE)
|
||||
SLOT_INTERFACE("multi", GROMPORT_MULTI)
|
||||
SLOT_INTERFACE("gkracker", GROMPORT_GK)
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
SLOT_INTERFACE_START( gromport8 )
|
||||
SLOT_INTERFACE("single", GROMPORT_SINGLE)
|
||||
SLOT_INTERFACE("multi", GROMPORT_MULTI)
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
INPUT_PORTS_START(gromport)
|
||||
PORT_START( "CARTRESET" )
|
||||
@ -310,16 +352,6 @@ void ti99_cartridge_connector_device::device_config_complete()
|
||||
m_gromport = static_cast<gromport_device*>(owner());
|
||||
}
|
||||
|
||||
UINT16 ti99_cartridge_connector_device::grom_base()
|
||||
{
|
||||
return m_gromport->get_grom_base();
|
||||
}
|
||||
|
||||
UINT16 ti99_cartridge_connector_device::grom_mask()
|
||||
{
|
||||
return m_gromport->get_grom_mask();
|
||||
}
|
||||
|
||||
single_conn_device::single_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: ti99_cartridge_connector_device(mconfig, GROMPORT_SINGLE, "Standard cartridge connector", tag, owner, clock, "single", __FILE__),
|
||||
m_cartridge(nullptr)
|
||||
@ -350,6 +382,28 @@ WRITE8_MEMBER(single_conn_device::cruwrite)
|
||||
m_cartridge->cruwrite(space, offset, data);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(single_conn_device::romgq_line)
|
||||
{
|
||||
// Pass through
|
||||
m_cartridge->romgq_line(state);
|
||||
}
|
||||
|
||||
/*
|
||||
Combined select lines
|
||||
*/
|
||||
WRITE8_MEMBER(single_conn_device::set_gromlines)
|
||||
{
|
||||
// Pass through
|
||||
m_cartridge->set_gromlines(space, offset, data);
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(single_conn_device::gclock_in)
|
||||
{
|
||||
// Pass through
|
||||
m_cartridge->gclock_in(state);
|
||||
}
|
||||
|
||||
void single_conn_device::device_start()
|
||||
{
|
||||
m_cartridge = static_cast<ti99_cartridge_device*>(subdevices().first());
|
||||
@ -475,10 +529,8 @@ int multi_conn_device::get_active_slot(bool changebase, offs_t offset)
|
||||
int slot;
|
||||
if (changebase)
|
||||
{
|
||||
if ((offset & grom_mask()) == grom_base())
|
||||
{
|
||||
set_slot((offset>>2) & 0x00ff);
|
||||
}
|
||||
// GROM selected?
|
||||
if (m_gsel != 0) set_slot((offset>>2) & 0x00ff);
|
||||
}
|
||||
slot = m_active_slot;
|
||||
return slot;
|
||||
@ -497,6 +549,50 @@ void multi_conn_device::remove(int index)
|
||||
m_cartridge[index] = nullptr;
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(multi_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(multi_conn_device::set_gromlines)
|
||||
{
|
||||
// GROM selected?
|
||||
m_gsel = data;
|
||||
|
||||
// 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(multi_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(multi_conn_device::readz)
|
||||
{
|
||||
int slot = get_active_slot(true, offset);
|
||||
@ -504,14 +600,14 @@ READ8Z_MEMBER(multi_conn_device::readz)
|
||||
// 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 ((offset & grom_mask()) == grom_base())
|
||||
if (m_gsel != 0)
|
||||
{
|
||||
for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
|
||||
{
|
||||
if (m_cartridge[i] != nullptr)
|
||||
{
|
||||
UINT8 newval = *value;
|
||||
m_cartridge[i]->readz(space, offset, &newval, mem_mask);
|
||||
m_cartridge[i]->readz(space, offset, &newval, 0xff);
|
||||
if (i==slot)
|
||||
{
|
||||
*value = newval;
|
||||
@ -523,33 +619,32 @@ READ8Z_MEMBER(multi_conn_device::readz)
|
||||
{
|
||||
if (slot < NUMBER_OF_CARTRIDGE_SLOTS && m_cartridge[slot] != nullptr)
|
||||
{
|
||||
m_cartridge[slot]->readz(space, offset, value, mem_mask);
|
||||
m_cartridge[slot]->readz(space, offset, value, 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(multi_conn_device::write)
|
||||
{
|
||||
int slot = get_active_slot(true, offset);
|
||||
|
||||
// Same issue as above (read)
|
||||
// We don't have GRAM cartridges, anyway, so it's just used for setting the address.
|
||||
if ((offset & grom_mask()) == grom_base())
|
||||
if (m_gsel != 0)
|
||||
{
|
||||
for (auto & elem : m_cartridge)
|
||||
{
|
||||
if (elem != nullptr)
|
||||
{
|
||||
elem->write(space, offset, data, mem_mask);
|
||||
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("%s: try it on slot %d\n", tag(), slot);
|
||||
m_cartridge[slot]->write(space, offset, data, mem_mask);
|
||||
// logerror("writing %04x (slot %d) <- %02x\n", offset, slot, data);
|
||||
m_cartridge[slot]->write(space, offset, data, 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -595,6 +690,7 @@ void multi_conn_device::device_reset(void)
|
||||
{
|
||||
m_active_slot = 0;
|
||||
m_fixed_slot = ioport("CARTSLOT")->read() - 1;
|
||||
m_gsel = 0;
|
||||
}
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT( multi_slot )
|
||||
@ -751,9 +847,40 @@ gkracker_device::gkracker_device(const machine_config &mconfig, const char *tag,
|
||||
{
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(gkracker_device::romgq_line)
|
||||
{
|
||||
if (m_cartridge != nullptr)
|
||||
{
|
||||
// Propagate to the guest
|
||||
m_cartridge->romgq_line(state);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Combined select lines
|
||||
*/
|
||||
WRITE8_MEMBER(gkracker_device::set_gromlines)
|
||||
{
|
||||
m_gsel = data;
|
||||
if (m_cartridge != nullptr)
|
||||
{
|
||||
// Propagate to the guest
|
||||
m_cartridge->set_gromlines(space, offset, data);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(gkracker_device::gclock_in)
|
||||
{
|
||||
if (m_cartridge != nullptr)
|
||||
{
|
||||
// Propagate to the guest
|
||||
m_cartridge->gclock_in(state);
|
||||
}
|
||||
}
|
||||
|
||||
READ8Z_MEMBER(gkracker_device::readz)
|
||||
{
|
||||
if ((offset & grom_mask()) == grom_base())
|
||||
if (m_gsel != 0)
|
||||
{
|
||||
// Reads from the GRAM space of the GRAM Kracker.
|
||||
|
||||
@ -863,7 +990,7 @@ WRITE8_MEMBER(gkracker_device::write)
|
||||
m_cartridge->write(space, offset, data, mem_mask);
|
||||
}
|
||||
|
||||
if ((offset & grom_mask()) == grom_base())
|
||||
if (m_gsel != 0)
|
||||
{
|
||||
// Write to the GRAM space of the GRAM Kracker.
|
||||
if ((offset & 0x0002)==0x0002)
|
||||
@ -1056,6 +1183,7 @@ void gkracker_device::device_reset()
|
||||
m_grom_address = 0; // for the GROM emulation
|
||||
m_ram_page = 0;
|
||||
m_waddr_LSB = false;
|
||||
m_gsel = 0;
|
||||
}
|
||||
|
||||
static MACHINE_CONFIG_FRAGMENT( gkracker_slot )
|
||||
@ -1270,15 +1398,15 @@ bool ti99_cartridge_device::has_grom()
|
||||
return m_pcb->m_grom_size>0;
|
||||
}
|
||||
|
||||
UINT16 ti99_cartridge_device::grom_base()
|
||||
{
|
||||
return m_connector->grom_base();
|
||||
}
|
||||
|
||||
UINT16 ti99_cartridge_device::grom_mask()
|
||||
{
|
||||
return m_connector->grom_mask();
|
||||
}
|
||||
// UINT16 ti99_cartridge_device::grom_base()
|
||||
// {
|
||||
// return m_connector->grom_base();
|
||||
// }
|
||||
//
|
||||
// UINT16 ti99_cartridge_device::grom_mask()
|
||||
// {
|
||||
// return m_connector->grom_mask();
|
||||
// }
|
||||
|
||||
bool ti99_cartridge_device::call_load()
|
||||
{
|
||||
@ -1401,12 +1529,14 @@ bool ti99_cartridge_device::call_softlist_load(software_list_device &swlist, con
|
||||
|
||||
READ8Z_MEMBER(ti99_cartridge_device::readz)
|
||||
{
|
||||
if (m_pcb != nullptr) m_pcb->readz(space, offset, value);
|
||||
if (m_pcb != nullptr)
|
||||
m_pcb->readz(space, offset, value);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(ti99_cartridge_device::write)
|
||||
{
|
||||
if (m_pcb != nullptr) m_pcb->write(space, offset, data);
|
||||
if (m_pcb != nullptr)
|
||||
m_pcb->write(space, offset, data);
|
||||
}
|
||||
|
||||
READ8Z_MEMBER(ti99_cartridge_device::crureadz)
|
||||
@ -1424,6 +1554,28 @@ WRITE_LINE_MEMBER( ti99_cartridge_device::ready_line )
|
||||
m_connector->ready_line(state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_cartridge_device::romgq_line )
|
||||
{
|
||||
if (m_pcb != nullptr)
|
||||
{
|
||||
m_pcb->romgq_line(state);
|
||||
m_readrom = state;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Combined select lines
|
||||
*/
|
||||
WRITE8_MEMBER(ti99_cartridge_device::set_gromlines)
|
||||
{
|
||||
if (m_pcb != nullptr) m_pcb->set_gromlines(space, offset, data);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(ti99_cartridge_device::gclock_in)
|
||||
{
|
||||
if (m_pcb != nullptr) m_pcb->gclock_in(state);
|
||||
}
|
||||
|
||||
void ti99_cartridge_device::device_config_complete()
|
||||
{
|
||||
update_names();
|
||||
@ -1431,41 +1583,15 @@ void ti99_cartridge_device::device_config_complete()
|
||||
m_connector = static_cast<ti99_cartridge_connector_device*>(owner());
|
||||
}
|
||||
|
||||
static GROM_CONFIG(grom3_config)
|
||||
{
|
||||
false, 3, CARTGROM_TAG, 0x0000, 0x1800, GROMFREQ
|
||||
};
|
||||
static GROM_CONFIG(grom4_config)
|
||||
{
|
||||
false, 4, CARTGROM_TAG, 0x2000, 0x1800, GROMFREQ
|
||||
};
|
||||
static GROM_CONFIG(grom5_config)
|
||||
{
|
||||
false, 5, CARTGROM_TAG, 0x4000, 0x1800, GROMFREQ
|
||||
};
|
||||
static GROM_CONFIG(grom6_config)
|
||||
{
|
||||
false, 6, CARTGROM_TAG, 0x6000, 0x1800, GROMFREQ
|
||||
};
|
||||
static GROM_CONFIG(grom7_config)
|
||||
{
|
||||
false, 7, CARTGROM_TAG, 0x8000, 0x1800, GROMFREQ
|
||||
};
|
||||
|
||||
/*
|
||||
5 GROMs that may be contained in a cartridge
|
||||
*/
|
||||
static MACHINE_CONFIG_FRAGMENT( ti99_cartridge )
|
||||
MCFG_GROM_ADD( GROM3_TAG, grom3_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_cartridge_device, ready_line))
|
||||
MCFG_GROM_ADD( GROM4_TAG, grom4_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_cartridge_device, ready_line))
|
||||
MCFG_GROM_ADD( GROM5_TAG, grom5_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_cartridge_device, ready_line))
|
||||
MCFG_GROM_ADD( GROM6_TAG, grom6_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_cartridge_device, ready_line))
|
||||
MCFG_GROM_ADD( GROM7_TAG, grom7_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_cartridge_device, ready_line))
|
||||
MCFG_GROM_ADD( GROM3_TAG, 3, CARTGROM_TAG, 0x0000, WRITELINE(ti99_cartridge_device, ready_line))
|
||||
MCFG_GROM_ADD( GROM4_TAG, 4, CARTGROM_TAG, 0x2000, WRITELINE(ti99_cartridge_device, ready_line))
|
||||
MCFG_GROM_ADD( GROM5_TAG, 5, CARTGROM_TAG, 0x4000, WRITELINE(ti99_cartridge_device, ready_line))
|
||||
MCFG_GROM_ADD( GROM6_TAG, 6, CARTGROM_TAG, 0x6000, WRITELINE(ti99_cartridge_device, ready_line))
|
||||
MCFG_GROM_ADD( GROM7_TAG, 7, CARTGROM_TAG, 0x8000, WRITELINE(ti99_cartridge_device, ready_line))
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
machine_config_constructor ti99_cartridge_device::device_mconfig_additions() const
|
||||
@ -1499,19 +1625,31 @@ const device_type TI99CART = &device_creator<ti99_cartridge_device>;
|
||||
Unlike in the previous implementation we do not model it as a full device.
|
||||
***************************************************************************/
|
||||
|
||||
ti99_cartridge_pcb::ti99_cartridge_pcb(): m_cart(nullptr), m_grom_size(0), m_rom_size(0), m_ram_size(0), m_rom_ptr(nullptr), m_ram_ptr(nullptr), m_rom_page(0), m_grom_ptr(nullptr), m_grom_address(0), m_ram_page(0), m_tag(nullptr)
|
||||
ti99_cartridge_pcb::ti99_cartridge_pcb()
|
||||
: m_cart(nullptr),
|
||||
m_grom_size(0),
|
||||
m_rom_size(0),
|
||||
m_ram_size(0),
|
||||
m_rom_ptr(nullptr),
|
||||
m_ram_ptr(nullptr),
|
||||
m_access_cartspace(false),
|
||||
m_rom_page(0),
|
||||
m_grom_ptr(nullptr),
|
||||
m_grom_address(0),
|
||||
m_ram_page(0),
|
||||
m_tag(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
UINT16 ti99_cartridge_pcb::grom_base()
|
||||
{
|
||||
return m_cart->grom_base();
|
||||
}
|
||||
|
||||
UINT16 ti99_cartridge_pcb::grom_mask()
|
||||
{
|
||||
return m_cart->grom_mask();
|
||||
}
|
||||
// UINT16 ti99_cartridge_pcb::grom_base()
|
||||
// {
|
||||
// return m_cart->grom_base();
|
||||
// }
|
||||
//
|
||||
// UINT16 ti99_cartridge_pcb::grom_mask()
|
||||
// {
|
||||
// return m_cart->grom_mask();
|
||||
// }
|
||||
|
||||
void ti99_cartridge_pcb::set_cartridge(ti99_cartridge_device *cart)
|
||||
{
|
||||
@ -1540,31 +1678,38 @@ WRITE8_MEMBER(ti99_cartridge_pcb::gromwrite)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TI-99/4A cartridges can only occupy 8 KiB of CPU RAM space. For TI-99/8
|
||||
cartridges with up to 16 KiB we need a new PCB type. Unfortunately, such
|
||||
cartridges were never developed.
|
||||
*/
|
||||
READ8Z_MEMBER(ti99_cartridge_pcb::readz)
|
||||
{
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
gromreadz(space, offset, value, mem_mask);
|
||||
else
|
||||
if (m_access_cartspace)
|
||||
{
|
||||
if (m_rom_ptr!=nullptr)
|
||||
{
|
||||
// For TI-99/8 we should plan for 16K cartridges. However, none was ever produced.
|
||||
// Well, forget about that.
|
||||
*value = m_rom_ptr[offset & 0x1fff];
|
||||
// logerror("%s: read cartridge rom space %04x = %02x\n", tag(), offset, *value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Will not return anything when not selected (preceding gsq=ASSERT)
|
||||
gromreadz(space, offset, value, mem_mask);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(ti99_cartridge_pcb::write)
|
||||
{
|
||||
// logerror("%s: write standard\n", tag());
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
gromwrite(space, offset, data, mem_mask);
|
||||
else
|
||||
if (m_access_cartspace)
|
||||
{
|
||||
if (TRACE_ILLWRITE) space.device().logerror("%s: Cannot write to ROM space at %04x\n", tag(), offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Will not change anything when not selected (preceding gsq=ASSERT)
|
||||
gromwrite(space, offset, data, mem_mask);
|
||||
}
|
||||
}
|
||||
|
||||
READ8Z_MEMBER(ti99_cartridge_pcb::crureadz)
|
||||
@ -1575,11 +1720,35 @@ WRITE8_MEMBER(ti99_cartridge_pcb::cruwrite)
|
||||
{
|
||||
}
|
||||
|
||||
inline void ti99_cartridge_pcb::set_grom_pointer(int number, device_t *dev)
|
||||
void ti99_cartridge_pcb::set_grom_pointer(int number, device_t *dev)
|
||||
{
|
||||
m_grom[number] = static_cast<ti99_grom_device*>(dev);
|
||||
m_grom[number] = static_cast<tmc0430_device*>(dev);
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_cartridge_pcb::romgq_line )
|
||||
{
|
||||
m_access_cartspace = (state==ASSERT_LINE);
|
||||
}
|
||||
|
||||
// Propagate to all GROMs
|
||||
|
||||
/*
|
||||
Combined select lines
|
||||
*/
|
||||
WRITE8_MEMBER(ti99_cartridge_pcb::set_gromlines)
|
||||
{
|
||||
for (auto& elem : m_grom)
|
||||
if (elem != nullptr) elem->set_lines(space, offset, data);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER(ti99_cartridge_pcb::gclock_in)
|
||||
{
|
||||
for (auto& elem : m_grom)
|
||||
if (elem != nullptr) elem->gclock_in(state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Cartridge type: Paged (Extended Basic)
|
||||
This cartridge consists of GROM memory and 2 pages of standard ROM.
|
||||
@ -1591,23 +1760,28 @@ inline void ti99_cartridge_pcb::set_grom_pointer(int number, device_t *dev)
|
||||
|
||||
READ8Z_MEMBER(ti99_paged_cartridge::readz)
|
||||
{
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
gromreadz(space, offset, value, mem_mask);
|
||||
else
|
||||
if (m_access_cartspace)
|
||||
{
|
||||
*value = m_rom_ptr[(offset & 0x1fff) | (m_rom_page << 13)];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Will not return anything when not selected (preceding gsq=ASSERT)
|
||||
gromreadz(space, offset, value, mem_mask);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER(ti99_paged_cartridge::write)
|
||||
{
|
||||
// logerror("%s: write standard\n", tag());
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
gromwrite(space, offset, data, mem_mask);
|
||||
|
||||
else {
|
||||
if (m_access_cartspace)
|
||||
{
|
||||
m_rom_page = (offset >> 1) & 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Will not change anything when not selected (preceding gsq=ASSERT)
|
||||
gromwrite(space, offset, data, mem_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -1620,10 +1794,7 @@ WRITE8_MEMBER(ti99_paged_cartridge::write)
|
||||
/* Read function for the minimem cartridge. */
|
||||
READ8Z_MEMBER(ti99_minimem_cartridge::readz)
|
||||
{
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
gromreadz(space, offset, value, mem_mask);
|
||||
|
||||
else
|
||||
if (m_access_cartspace)
|
||||
{
|
||||
if ((offset & 0x1000)==0x0000)
|
||||
{
|
||||
@ -1637,16 +1808,16 @@ READ8Z_MEMBER(ti99_minimem_cartridge::readz)
|
||||
*value = m_ram_ptr[offset & 0x0fff];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gromreadz(space, offset, value, mem_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write function for the minimem cartridge. */
|
||||
WRITE8_MEMBER(ti99_minimem_cartridge::write)
|
||||
{
|
||||
// logerror("%s: write standard\n", tag());
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
gromwrite(space, offset, data, mem_mask);
|
||||
|
||||
else
|
||||
if (m_access_cartspace)
|
||||
{
|
||||
if ((offset & 0x1000)==0x0000)
|
||||
{
|
||||
@ -1657,6 +1828,10 @@ WRITE8_MEMBER(ti99_minimem_cartridge::write)
|
||||
m_ram_ptr[offset & 0x0fff] = data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gromwrite(space, offset, data, mem_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -1678,26 +1853,30 @@ WRITE8_MEMBER(ti99_minimem_cartridge::write)
|
||||
/* Read function for the super cartridge. */
|
||||
READ8Z_MEMBER(ti99_super_cartridge::readz)
|
||||
{
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
gromreadz(space, offset, value, mem_mask);
|
||||
else
|
||||
if (m_access_cartspace)
|
||||
{
|
||||
if (m_ram_ptr != nullptr)
|
||||
{
|
||||
*value = m_ram_ptr[(m_ram_page << 13) | (offset & 0x1fff)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gromreadz(space, offset, value, mem_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write function for the super cartridge. */
|
||||
WRITE8_MEMBER(ti99_super_cartridge::write)
|
||||
{
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
gromwrite(space, offset, data, mem_mask);
|
||||
else
|
||||
if (m_access_cartspace)
|
||||
{
|
||||
m_ram_ptr[(m_ram_page << 13) | (offset & 0x1fff)] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
gromwrite(space, offset, data, mem_mask);
|
||||
}
|
||||
}
|
||||
|
||||
READ8Z_MEMBER(ti99_super_cartridge::crureadz)
|
||||
@ -1763,9 +1942,7 @@ WRITE8_MEMBER(ti99_super_cartridge::cruwrite)
|
||||
/* Read function for the mbx cartridge. */
|
||||
READ8Z_MEMBER(ti99_mbx_cartridge::readz)
|
||||
{
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
gromreadz(space, offset, value, mem_mask);
|
||||
else
|
||||
if (m_access_cartspace)
|
||||
{
|
||||
if ((offset & 0x1c00)==0x0c00)
|
||||
{
|
||||
@ -1781,14 +1958,16 @@ READ8Z_MEMBER(ti99_mbx_cartridge::readz)
|
||||
*value = m_rom_ptr[(offset & 0x1fff) | (m_rom_page<<13)];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gromreadz(space, offset, value, mem_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/* Write function for the mbx cartridge. */
|
||||
WRITE8_MEMBER(ti99_mbx_cartridge::write)
|
||||
{
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
gromwrite(space, offset, data, mem_mask);
|
||||
else
|
||||
if (m_access_cartspace)
|
||||
{
|
||||
if (offset == 0x6ffe)
|
||||
{
|
||||
@ -1802,6 +1981,10 @@ WRITE8_MEMBER(ti99_mbx_cartridge::write)
|
||||
m_ram_ptr[offset & 0x03ff] = data;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gromwrite(space, offset, data, mem_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -2032,9 +2215,15 @@ WRITE8_MEMBER(ti99_pagedcru_cartridge::cruwrite)
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
WRITE_LINE_MEMBER(ti99_gromemu_cartridge::gsq_line)
|
||||
{
|
||||
m_grom_space = (state==ASSERT_LINE);
|
||||
}
|
||||
|
||||
|
||||
READ8Z_MEMBER(ti99_gromemu_cartridge::readz)
|
||||
{
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
if (m_grom_space)
|
||||
gromemureadz(space, offset, value, mem_mask);
|
||||
else
|
||||
{
|
||||
@ -2055,8 +2244,7 @@ READ8Z_MEMBER(ti99_gromemu_cartridge::readz)
|
||||
|
||||
WRITE8_MEMBER(ti99_gromemu_cartridge::write)
|
||||
{
|
||||
// logerror("%s: write standard\n", tag());
|
||||
if ((offset & grom_mask())==grom_base())
|
||||
if (m_grom_space)
|
||||
gromemuwrite(space, offset, data, mem_mask);
|
||||
|
||||
else {
|
||||
@ -2179,7 +2367,7 @@ rpk::rpk(emu_options& options, const char* sysname)
|
||||
|
||||
rpk::~rpk()
|
||||
{
|
||||
//if (TRACE_RPK) logerror("gromport/RPK: Destroy RPK\n");
|
||||
if (TRACE_RPK) printf("gromport/RPK: Destroy RPK\n");
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2290,7 +2478,7 @@ rpk_socket* rpk_reader::load_rom_resource(util::archive_file &zip, xml_data_node
|
||||
file = xml_get_attribute_string(rom_resource_node, "file", nullptr);
|
||||
if (file == nullptr) throw rpk_exception(RPK_INVALID_LAYOUT, "<rom> must have a 'file' attribute");
|
||||
|
||||
//if (TRACE_RPK) logerror("gromport/RPK: Loading ROM contents for socket '%s' from file %s\n", socketname, file);
|
||||
if (TRACE_RPK) printf("gromport/RPK: Loading ROM contents for socket '%s' from file %s\n", socketname, file);
|
||||
|
||||
// check for crc
|
||||
crcstr = xml_get_attribute_string(rom_resource_node, "crc", nullptr);
|
||||
@ -2378,7 +2566,7 @@ rpk_socket* rpk_reader::load_ram_resource(emu_options &options, xml_data_node* r
|
||||
contents = global_alloc_array_clear<UINT8>(length);
|
||||
if (contents==nullptr) throw rpk_exception(RPK_OUT_OF_MEMORY);
|
||||
|
||||
//if (TRACE_RPK) logerror("gromport/RPK: Allocating RAM buffer (%d bytes) for socket '%s'\n", length, socketname);
|
||||
if (TRACE_RPK) printf("gromport/RPK: Allocating RAM buffer (%d bytes) for socket '%s'\n", length, socketname);
|
||||
|
||||
ram_pname = nullptr;
|
||||
|
||||
@ -2400,7 +2588,7 @@ rpk_socket* rpk_reader::load_ram_resource(emu_options &options, xml_data_node* r
|
||||
std::string ram_pathname = std::string(system_name).append(PATH_SEPARATOR).append(ram_filename);
|
||||
ram_pname = core_strdup(ram_pathname.c_str());
|
||||
// load, and fill rest with 00
|
||||
//if (TRACE_RPK) logerror("gromport/RPK: Loading NVRAM contents from '%s'\n", ram_pname);
|
||||
if (TRACE_RPK) printf("gromport/RPK: Loading NVRAM contents from '%s'\n", ram_pname);
|
||||
image_battery_load_by_name(options, ram_pname, contents, length, 0x00);
|
||||
}
|
||||
}
|
||||
@ -2488,7 +2676,7 @@ rpk* rpk_reader::open(emu_options &options, const char *filename, const char *sy
|
||||
// We'll try to find the PCB type on the provided type list.
|
||||
pcb_type = xml_get_attribute_string(pcb_node, "type", nullptr);
|
||||
if (pcb_type==nullptr) throw rpk_exception(RPK_INVALID_LAYOUT, "<pcb> must have a 'type' attribute");
|
||||
//if (TRACE_RPK) logerror("gromport/RPK: Cartridge says it has PCB type '%s'\n", pcb_type);
|
||||
if (TRACE_RPK) printf("gromport/RPK: Cartridge says it has PCB type '%s'\n", pcb_type);
|
||||
|
||||
i=0;
|
||||
do
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
#include "emu.h"
|
||||
#include "ti99defs.h"
|
||||
#include "grom.h"
|
||||
#include "machine/tmc0430.h"
|
||||
|
||||
extern const device_type GROMPORT;
|
||||
|
||||
@ -29,13 +29,22 @@ public:
|
||||
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 object) { return downcast<gromport_device &>(device).m_console_ready.set_callback(object); }
|
||||
template<class _Object> static devcb_base &static_set_reset_callback(device_t &device, _Object object) { return downcast<gromport_device &>(device).m_console_reset.set_callback(object); }
|
||||
|
||||
void cartridge_inserted();
|
||||
void set_grom_base(UINT16 grombase, UINT16 grommask);
|
||||
UINT16 get_grom_base() { return m_grombase; }
|
||||
UINT16 get_grom_mask() { return m_grommask; }
|
||||
// void set_grom_base(UINT16 grombase, UINT16 grommask);
|
||||
// UINT16 get_grom_base() { return m_grombase; }
|
||||
// UINT16 get_grom_mask() { return m_grommask; }
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
@ -48,15 +57,24 @@ private:
|
||||
bool m_reset_on_insert;
|
||||
devcb_write_line m_console_ready;
|
||||
devcb_write_line m_console_reset;
|
||||
UINT16 m_grombase;
|
||||
UINT16 m_grommask;
|
||||
int m_mask;
|
||||
int m_romgq;
|
||||
// UINT16 m_grombase;
|
||||
// UINT16 m_grommask;
|
||||
};
|
||||
|
||||
SLOT_INTERFACE_EXTERN(gromport);
|
||||
SLOT_INTERFACE_EXTERN(gromport4);
|
||||
SLOT_INTERFACE_EXTERN(gromport8);
|
||||
|
||||
#define MCFG_TI99_GROMPORT_ADD( _tag ) \
|
||||
#define MCFG_GROMPORT4_ADD( _tag ) \
|
||||
MCFG_DEVICE_ADD(_tag, GROMPORT, 0) \
|
||||
MCFG_DEVICE_SLOT_INTERFACE(gromport, "single", false)
|
||||
gromport_device::set_mask(*device, 0x1fff); \
|
||||
MCFG_DEVICE_SLOT_INTERFACE(gromport4, "single", false)
|
||||
|
||||
#define MCFG_GROMPORT8_ADD( _tag ) \
|
||||
MCFG_DEVICE_ADD(_tag, GROMPORT, 0) \
|
||||
gromport_device::set_mask(*device, 0x3fff); \
|
||||
MCFG_DEVICE_SLOT_INTERFACE(gromport8, "single", false)
|
||||
|
||||
#define MCFG_GROMPORT_READY_HANDLER( _ready ) \
|
||||
devcb = &gromport_device::static_set_ready_callback( *device, DEVCB_##_ready );
|
||||
@ -80,11 +98,16 @@ public:
|
||||
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; }
|
||||
bool has_grom();
|
||||
void set_slot(int i);
|
||||
UINT16 grom_base();
|
||||
UINT16 grom_mask();
|
||||
// UINT16 grom_base();
|
||||
// UINT16 grom_mask();
|
||||
|
||||
protected:
|
||||
virtual void device_start() override { };
|
||||
@ -111,6 +134,7 @@ protected:
|
||||
const option_guide *create_option_guide() const override { return nullptr; }
|
||||
|
||||
private:
|
||||
bool m_readrom;
|
||||
bool m_softlist;
|
||||
int m_pcbtype;
|
||||
int m_slot;
|
||||
@ -136,18 +160,24 @@ 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) { };
|
||||
UINT16 grom_base();
|
||||
UINT16 grom_mask();
|
||||
// UINT16 grom_base();
|
||||
// UINT16 grom_mask();
|
||||
|
||||
protected:
|
||||
ti99_cartridge_connector_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
|
||||
virtual void device_config_complete() override;
|
||||
|
||||
gromport_device* m_gromport;
|
||||
int m_gsel;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -162,6 +192,9 @@ public:
|
||||
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;
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
@ -190,6 +223,9 @@ public:
|
||||
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;
|
||||
@ -201,6 +237,7 @@ protected:
|
||||
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;
|
||||
@ -222,6 +259,9 @@ public:
|
||||
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;
|
||||
@ -275,23 +315,28 @@ protected:
|
||||
virtual DECLARE_READ8Z_MEMBER(crureadz);
|
||||
virtual DECLARE_WRITE8_MEMBER(cruwrite);
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(romgq_line);
|
||||
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);
|
||||
UINT16 grom_base();
|
||||
UINT16 grom_mask();
|
||||
// UINT16 grom_base();
|
||||
// UINT16 grom_mask();
|
||||
const char* tag() { return m_tag; }
|
||||
void set_tag(const char* tag) { m_tag = tag; }
|
||||
|
||||
ti99_cartridge_device* m_cart;
|
||||
ti99_grom_device* m_grom[5];
|
||||
tmc0430_device* m_grom[5];
|
||||
int m_grom_size;
|
||||
int m_rom_size;
|
||||
int m_ram_size;
|
||||
|
||||
UINT8* m_rom_ptr;
|
||||
UINT8* m_ram_ptr;
|
||||
bool m_access_cartspace;
|
||||
int m_rom_page; // for some cartridge types
|
||||
UINT8* m_grom_ptr; // for gromemu
|
||||
int m_grom_address; // for gromemu
|
||||
@ -398,15 +443,19 @@ public:
|
||||
class ti99_gromemu_cartridge : public ti99_cartridge_pcb
|
||||
{
|
||||
public:
|
||||
ti99_gromemu_cartridge(): m_waddr_LSB(false)
|
||||
ti99_gromemu_cartridge(): m_waddr_LSB(false), m_grom_space(false)
|
||||
{ m_grom_address = 0; }
|
||||
~ti99_gromemu_cartridge() { };
|
||||
DECLARE_READ8Z_MEMBER(readz) override;
|
||||
DECLARE_WRITE8_MEMBER(write) override;
|
||||
DECLARE_READ8Z_MEMBER(gromemureadz);
|
||||
DECLARE_WRITE8_MEMBER(gromemuwrite);
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(gsq_line);
|
||||
|
||||
private:
|
||||
bool m_waddr_LSB;
|
||||
bool m_grom_space;
|
||||
};
|
||||
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define JOYPORT_TAG "joyport"
|
||||
#define VDP_TAG "vdp"
|
||||
#define DSRROM "dsrrom"
|
||||
#define CONSOLEROM "consolerom"
|
||||
|
||||
#define VDPFREQ XTAL_10_738635MHz
|
||||
#define GROMFREQ VDPFREQ/24
|
||||
@ -41,10 +42,49 @@
|
||||
#define DRAM_TAG "dram8"
|
||||
#define MAPPER_TAG "mapper"
|
||||
#define MAINBOARD8_TAG "mainboard8"
|
||||
#define SPEECH_TAG "speech"
|
||||
#define ROM0_TAG "rom0"
|
||||
#define ROM1_TAG "rom1"
|
||||
#define PCODEROM_TAG "pcode"
|
||||
#define SPEECHSYN_TAG "speech"
|
||||
|
||||
#define ROM0_REG "rom0_region"
|
||||
#define ROM1_REG "rom1_region"
|
||||
#define PASCAL_REG "pascal_region"
|
||||
#define SYSGROM_REG "sysgrom_region"
|
||||
#define GROMLIB1_REG "gromlib1_region"
|
||||
#define GROMLIB2_REG "gromlib2_region"
|
||||
#define GROMLIB3_REG "gromlib3_region"
|
||||
#define SPEECHROM_REG "speech_region"
|
||||
|
||||
#define GROMLIB_TAG "gromlib"
|
||||
#define SYSGROM_TAG GROMLIB_TAG "0"
|
||||
#define SYSGROM0_TAG SYSGROM_TAG "_0"
|
||||
#define SYSGROM1_TAG SYSGROM_TAG "_1"
|
||||
#define SYSGROM2_TAG SYSGROM_TAG "_2"
|
||||
|
||||
#define GLIB1_TAG GROMLIB_TAG "1"
|
||||
#define GLIB10_TAG GLIB1_TAG "_0"
|
||||
#define GLIB11_TAG GLIB1_TAG "_1"
|
||||
#define GLIB12_TAG GLIB1_TAG "_2"
|
||||
#define GLIB13_TAG GLIB1_TAG "_3"
|
||||
#define GLIB14_TAG GLIB1_TAG "_4"
|
||||
#define GLIB15_TAG GLIB1_TAG "_5"
|
||||
#define GLIB16_TAG GLIB1_TAG "_6"
|
||||
#define GLIB17_TAG GLIB1_TAG "_7"
|
||||
|
||||
#define GLIB2_TAG GROMLIB_TAG "2"
|
||||
#define GLIB20_TAG GLIB2_TAG "_0"
|
||||
#define GLIB21_TAG GLIB2_TAG "_1"
|
||||
#define GLIB22_TAG GLIB2_TAG "_2"
|
||||
#define GLIB23_TAG GLIB2_TAG "_3"
|
||||
#define GLIB24_TAG GLIB2_TAG "_4"
|
||||
#define GLIB25_TAG GLIB2_TAG "_5"
|
||||
#define GLIB26_TAG GLIB2_TAG "_6"
|
||||
#define GLIB27_TAG GLIB2_TAG "_7"
|
||||
|
||||
#define GLIB3_TAG GROMLIB_TAG "3"
|
||||
#define GLIB30_TAG GLIB3_TAG "_0"
|
||||
#define GLIB31_TAG GLIB3_TAG "_1"
|
||||
#define GLIB32_TAG GLIB3_TAG "_2"
|
||||
|
||||
|
||||
|
||||
// Geneve
|
||||
#define GKEYBOARD_TAG "gkeyboard"
|
||||
|
@ -39,7 +39,9 @@ ti_std_video_device::ti_std_video_device(const machine_config &mconfig, const ch
|
||||
}
|
||||
|
||||
ti_exp_video_device::ti_exp_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: ti_video_device(mconfig, V9938VIDEO, "TI99 EXP Video subsystem", tag, owner, clock, "v9938_video", __FILE__), m_v9938(nullptr)
|
||||
: ti_video_device(mconfig, V9938VIDEO, "TI99 EXP Video subsystem", tag, owner, clock, "v9938_video", __FILE__),
|
||||
m_v9938(nullptr),
|
||||
m_out_gromclk_cb(*this)
|
||||
{
|
||||
}
|
||||
|
||||
@ -129,6 +131,14 @@ WRITE16_MEMBER( ti_exp_video_device::write16 )
|
||||
}
|
||||
}
|
||||
|
||||
void ti_exp_video_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
// Pulse it
|
||||
m_out_gromclk_cb(ASSERT_LINE);
|
||||
m_out_gromclk_cb(CLEAR_LINE);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/*
|
||||
@ -194,10 +204,13 @@ void ti_video_device::device_start(void)
|
||||
void ti_exp_video_device::device_start(void)
|
||||
{
|
||||
m_v9938 = static_cast<v9938_device*>(machine().device(VDP_TAG));
|
||||
m_out_gromclk_cb.resolve();
|
||||
m_gromclk_timer = timer_alloc(0);
|
||||
}
|
||||
|
||||
void ti_video_device::device_reset(void)
|
||||
void ti_exp_video_device::device_reset(void)
|
||||
{
|
||||
if (!m_out_gromclk_cb.isnull()) m_gromclk_timer->adjust(attotime::zero, 0, attotime::from_hz(XTAL_10_738635MHz/24));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
@ -30,7 +30,7 @@ protected:
|
||||
/* Constructor */
|
||||
ti_video_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
|
||||
virtual void device_start(void) override;
|
||||
virtual void device_reset(void) override;
|
||||
virtual void device_reset(void) override { };
|
||||
virtual DECLARE_READ8Z_MEMBER(readz) override { };
|
||||
virtual DECLARE_WRITE8_MEMBER(write) override { };
|
||||
};
|
||||
@ -55,6 +55,8 @@ class ti_exp_video_device : public ti_video_device
|
||||
{
|
||||
public:
|
||||
ti_exp_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
template<class _Object> static devcb_base &set_out_gromclk_callback(device_t &device, _Object object) { return downcast<ti_exp_video_device &>(device).m_out_gromclk_cb.set_callback(object); }
|
||||
|
||||
void video_update_mouse(int delta_x, int delta_y, int buttons);
|
||||
DECLARE_READ8Z_MEMBER(readz) override;
|
||||
DECLARE_WRITE8_MEMBER(write) override;
|
||||
@ -63,10 +65,20 @@ public:
|
||||
void reset_vdp(int state) override { m_v9938->reset_line(state); }
|
||||
|
||||
protected:
|
||||
virtual void device_start(void) override;
|
||||
v9938_device *m_v9938;
|
||||
virtual void device_start(void) override;
|
||||
virtual void device_reset(void) override;
|
||||
|
||||
private:
|
||||
void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
v9938_device *m_v9938;
|
||||
devcb_write_line m_out_gromclk_cb; // GROMCLK line is optional; if present, pulse it by XTAL/24 rate
|
||||
emu_timer *m_gromclk_timer;
|
||||
};
|
||||
|
||||
#define MCFG_ADD_GROMCLK_CB(_devcb) \
|
||||
devcb = &ti_exp_video_device::set_out_gromclk_callback(*device, DEVCB_##_devcb);
|
||||
|
||||
|
||||
extern const device_type TI99VIDEO;
|
||||
extern const device_type V9938VIDEO;
|
||||
|
||||
@ -131,35 +143,39 @@ protected:
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#define MCFG_TI_TMS991x_ADD_NTSC(_tag, _chip, _vsize, _class, _int) \
|
||||
#define MCFG_TI_TMS991x_ADD_NTSC(_tag, _chip, _vsize, _class, _int, _gclk) \
|
||||
MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \
|
||||
MCFG_DEVICE_ADD( VDP_TAG, _chip, XTAL_10_738635MHz / 2 ) \
|
||||
MCFG_TMS9928A_VRAM_SIZE(_vsize) \
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(_class,_int)) \
|
||||
MCFG_TMS9928A_OUT_GROMCLK_CB(WRITELINE(_class,_gclk)) \
|
||||
MCFG_TMS9928A_SCREEN_ADD_NTSC( SCREEN_TAG ) \
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
|
||||
#define MCFG_TI_TMS991x_ADD_PAL(_tag, _chip, _vsize, _class, _int) \
|
||||
#define MCFG_TI_TMS991x_ADD_PAL(_tag, _chip, _vsize, _class, _int, _gclk) \
|
||||
MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \
|
||||
MCFG_DEVICE_ADD( VDP_TAG, _chip, XTAL_10_738635MHz / 2 ) \
|
||||
MCFG_TMS9928A_VRAM_SIZE(_vsize) \
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(_class,_int)) \
|
||||
MCFG_TMS9928A_OUT_GROMCLK_CB(WRITELINE(_class,_gclk)) \
|
||||
MCFG_TMS9928A_SCREEN_ADD_PAL( SCREEN_TAG ) \
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
|
||||
#define MCFG_TI998_ADD_NTSC(_tag, _chip, _vsize, _class, _int) \
|
||||
#define MCFG_TI998_ADD_NTSC(_tag, _chip, _vsize, _class, _int, _gclk) \
|
||||
MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \
|
||||
MCFG_DEVICE_ADD( VDP_TAG, _chip, XTAL_10_738635MHz / 2 ) \
|
||||
MCFG_TMS9928A_VRAM_SIZE(_vsize) \
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(_class,_int)) \
|
||||
MCFG_TMS9928A_OUT_GROMCLK_CB(WRITELINE(_class,_gclk)) \
|
||||
MCFG_TMS9928A_SCREEN_ADD_NTSC( SCREEN_TAG ) \
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
|
||||
#define MCFG_TI998_ADD_PAL(_tag, _chip, _vsize, _class, _int) \
|
||||
#define MCFG_TI998_ADD_PAL(_tag, _chip, _vsize, _class, _int, _gclk) \
|
||||
MCFG_DEVICE_ADD(_tag, TI99VIDEO, 0) \
|
||||
MCFG_DEVICE_ADD( VDP_TAG, _chip, XTAL_10_738635MHz / 2 ) \
|
||||
MCFG_TMS9928A_VRAM_SIZE(_vsize) \
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(_class,_int)) \
|
||||
MCFG_TMS9928A_OUT_GROMCLK_CB(WRITELINE(_class,_gclk)) \
|
||||
MCFG_TMS9928A_SCREEN_ADD_PAL( SCREEN_TAG ) \
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
|
||||
|
@ -439,12 +439,16 @@ READ16_MEMBER( ti99_4p_state::datamux_read )
|
||||
UINT8 hbyte = 0;
|
||||
UINT16 addroff = (offset << 1);
|
||||
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
|
||||
m_peribox->readz(space, addroff+1, &m_latch, mem_mask);
|
||||
m_lowbyte = m_latch;
|
||||
|
||||
m_peribox->readz(space, addroff, &hbyte, mem_mask);
|
||||
m_highbyte = hbyte;
|
||||
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
|
||||
// use the latch and the currently read byte and put it on the 16bit bus
|
||||
// printf("read address = %04x, value = %04x, memmask = %4x\n", addroff, (hbyte<<8) | sgcpu->latch, mem_mask);
|
||||
|
||||
@ -467,11 +471,15 @@ WRITE16_MEMBER( ti99_4p_state::datamux_write )
|
||||
// read more about the datamux in datamux.c
|
||||
|
||||
// Write to the PEB
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
|
||||
m_peribox->write(space, addroff+1, data & 0xff);
|
||||
|
||||
// Write to the PEB
|
||||
m_peribox->write(space, addroff, (data>>8) & 0xff);
|
||||
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
|
||||
// Insert four wait states and let CPU enter wait state
|
||||
m_waitcount = 6;
|
||||
console_ready_dmux(CLEAR_LINE);
|
||||
|
@ -48,7 +48,6 @@
|
||||
|
||||
#include "bus/ti99x/videowrp.h"
|
||||
#include "bus/ti99x/datamux.h"
|
||||
#include "bus/ti99x/grom.h"
|
||||
#include "bus/ti99x/gromport.h"
|
||||
#include "bus/ti99x/joyport.h"
|
||||
|
||||
@ -103,6 +102,9 @@ public:
|
||||
DECLARE_WRITE_LINE_MEMBER( console_reset );
|
||||
DECLARE_WRITE_LINE_MEMBER( notconnected );
|
||||
|
||||
// GROM clock
|
||||
DECLARE_WRITE_LINE_MEMBER( gromclk_in );
|
||||
|
||||
// Connections with the system interface chip 9901
|
||||
DECLARE_WRITE_LINE_MEMBER( extint );
|
||||
DECLARE_WRITE_LINE_MEMBER( video_interrupt_in );
|
||||
@ -177,16 +179,10 @@ enum
|
||||
};
|
||||
|
||||
/*
|
||||
Memory map.
|
||||
Most of the work is done in the datamux (see datamux.c). We only keep ROM
|
||||
and the small 256 byte PAD RAM here because they are directly connected
|
||||
to the 16bit bus, and the wait state logic is not active during their
|
||||
accesses.
|
||||
Memory map. All of the work is done in the datamux (see datamux.c).
|
||||
*/
|
||||
static ADDRESS_MAP_START(memmap, AS_PROGRAM, 16, ti99_4x_state)
|
||||
ADDRESS_MAP_GLOBAL_MASK(0xffff)
|
||||
AM_RANGE(0x0000, 0x1fff) AM_ROM
|
||||
AM_RANGE(0x8000, 0x80ff) AM_MIRROR(0x0300) AM_RAM
|
||||
AM_RANGE(0x0000, 0xffff) AM_DEVREADWRITE(DATAMUX_TAG, ti99_datamux_device, read, write) AM_DEVSETOFFSET(DATAMUX_TAG, ti99_datamux_device, setoffset)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
@ -365,21 +361,6 @@ INPUT_PORTS_END
|
||||
Components
|
||||
******************************************************************************/
|
||||
|
||||
static GROM_CONFIG(grom0_config)
|
||||
{
|
||||
false, 0, region_grom, 0x0000, 0x1800, GROMFREQ
|
||||
};
|
||||
|
||||
static GROM_CONFIG(grom1_config)
|
||||
{
|
||||
false, 1, region_grom, 0x2000, 0x1800, GROMFREQ
|
||||
};
|
||||
|
||||
static GROM_CONFIG(grom2_config)
|
||||
{
|
||||
false, 2, region_grom, 0x4000, 0x1800, GROMFREQ
|
||||
};
|
||||
|
||||
READ8_MEMBER( ti99_4x_state::cruread )
|
||||
{
|
||||
// if (TRACE_CRU) logerror("read access to CRU address %04x\n", offset << 4);
|
||||
@ -631,6 +612,7 @@ READ8_MEMBER( ti99_4x_state::interrupt_level )
|
||||
WRITE_LINE_MEMBER( ti99_4x_state::clock_out )
|
||||
{
|
||||
m_datamux->clock_in(state);
|
||||
m_peribox->clock_in(state);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -641,6 +623,15 @@ WRITE_LINE_MEMBER( ti99_4x_state::dbin_line )
|
||||
m_datamux->dbin_in(state);
|
||||
}
|
||||
|
||||
/*
|
||||
GROMCLK from VDP, propagating to datamux
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_4x_state::gromclk_in )
|
||||
{
|
||||
m_datamux->gromclk_in(state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
@ -708,6 +699,7 @@ void ti99_4x_state::console_ready_join(int id, int state)
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_4x_state::console_ready_grom )
|
||||
{
|
||||
if (TRACE_READY) logerror("GROM ready = %d\n", state);
|
||||
console_ready_join(READY_GROM, state);
|
||||
}
|
||||
|
||||
@ -757,52 +749,6 @@ WRITE_LINE_MEMBER( ti99_4x_state::notconnected )
|
||||
if (TRACE_INTERRUPTS) logerror("ti99_4x: Setting a not connected line ... ignored\n");
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
Devices attached to the databus multiplexer. We cannot solve this with
|
||||
the common address maps since the multiplexer also inserts wait states
|
||||
that we want to emulate properly. Also, devices may reside on the same
|
||||
memory locations (like GROMs) and select themselves according to some
|
||||
inner state (e.g. GROMs have an own address counter and a given address
|
||||
area).
|
||||
*/
|
||||
static const dmux_device_list_entry dmux_devices[] =
|
||||
{
|
||||
{ VIDEO_SYSTEM_TAG, 0x8800, 0xfc01, 0x0400, nullptr, 0, 0 },
|
||||
{ GROM0_TAG, 0x9800, 0xfc01, 0x0400, "GROMENA", 0x01, 0x00 },
|
||||
{ GROM1_TAG, 0x9800, 0xfc01, 0x0400, "GROMENA", 0x01, 0x00 },
|
||||
{ GROM2_TAG, 0x9800, 0xfc01, 0x0400, "GROMENA", 0x01, 0x00 },
|
||||
{ TISOUND_TAG, 0x8400, 0xfc01, 0x0000, nullptr, 0, 0 },
|
||||
{ GROMPORT_TAG, 0x9800, 0xfc01, 0x0400, nullptr, 0, 0 },
|
||||
{ GROMPORT_TAG, 0x6000, 0xe000, 0x0000, nullptr, 0, 0 },
|
||||
{ PERIBOX_TAG, 0x0000, 0x0000, 0x0000, nullptr, 0, 0 }, // Peribox needs all addresses
|
||||
{ nullptr, 0, 0, 0, nullptr, 0, 0 }
|
||||
};
|
||||
|
||||
static const dmux_device_list_entry dmux_devices_ev[] =
|
||||
{
|
||||
{ VIDEO_SYSTEM_TAG, 0x8800, 0xfc01, 0x0400, nullptr, 0, 0 },
|
||||
{ GROM0_TAG, 0x9800, 0xfc01, 0x0400, "GROMENA", 0x01, 0x00 },
|
||||
{ GROM1_TAG, 0x9800, 0xfc01, 0x0400, "GROMENA", 0x01, 0x00 },
|
||||
{ GROM2_TAG, 0x9800, 0xfc01, 0x0400, "GROMENA", 0x01, 0x00 },
|
||||
{ TISOUND_TAG, 0x8400, 0xfc01, 0x0000, nullptr, 0, 0 },
|
||||
{ GROMPORT_TAG, 0x9800, 0xfc01, 0x0400, nullptr, 0, 0 },
|
||||
{ GROMPORT_TAG, 0x6000, 0xe000, 0x0000, nullptr, 0, 0 },
|
||||
{ PERIBOX_TAG, 0x0000, 0x0000, 0x0000, nullptr, 0, 0 }, // Peribox needs all addresses
|
||||
{ nullptr, 0, 0, 0, nullptr, 0, 0 }
|
||||
};
|
||||
|
||||
static DMUX_CONFIG( datamux_conf )
|
||||
{
|
||||
dmux_devices
|
||||
};
|
||||
|
||||
static DMUX_CONFIG( datamux_conf_ev )
|
||||
{
|
||||
dmux_devices_ev
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
Machine definitions
|
||||
******************************************************************************/
|
||||
@ -852,9 +798,10 @@ static MACHINE_CONFIG_START( ti99_4, ti99_4x_state )
|
||||
MCFG_TMS9901_P9_HANDLER( WRITELINE( ti99_4x_state, cassette_output) )
|
||||
MCFG_TMS9901_INTLEVEL_HANDLER( WRITE8( ti99_4x_state, tms9901_interrupt) )
|
||||
|
||||
MCFG_DMUX_ADD( DATAMUX_TAG, datamux_conf )
|
||||
MCFG_DEVICE_ADD( DATAMUX_TAG, DATAMUX, 0)
|
||||
MCFG_DMUX_READY_HANDLER( WRITELINE(ti99_4x_state, console_ready_dmux) )
|
||||
MCFG_TI99_GROMPORT_ADD( GROMPORT_TAG )
|
||||
|
||||
MCFG_GROMPORT4_ADD( GROMPORT_TAG )
|
||||
MCFG_GROMPORT_READY_HANDLER( WRITELINE(ti99_4x_state, console_ready_cart) )
|
||||
MCFG_GROMPORT_RESET_HANDLER( WRITELINE(ti99_4x_state, console_reset) )
|
||||
|
||||
@ -879,13 +826,10 @@ static MACHINE_CONFIG_START( ti99_4, ti99_4x_state )
|
||||
MCFG_SOUND_WAVE_ADD(WAVE_TAG, "cassette")
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "cass_out", 0.25)
|
||||
|
||||
/* GROM devices */
|
||||
MCFG_GROM_ADD( GROM0_TAG, grom0_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM1_TAG, grom1_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM2_TAG, grom2_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
// GROM devices
|
||||
MCFG_GROM_ADD( GROM0_TAG, 0, region_grom, 0x0000, WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM1_TAG, 1, region_grom, 0x2000, WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM2_TAG, 2, region_grom, 0x4000, WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
|
||||
// Joystick port
|
||||
MCFG_TI_JOYPORT4_ADD( JOYPORT_TAG )
|
||||
@ -896,14 +840,14 @@ MACHINE_CONFIG_END
|
||||
US version: 60 Hz, NTSC
|
||||
*/
|
||||
static MACHINE_CONFIG_DERIVED( ti99_4_60hz, ti99_4 )
|
||||
MCFG_TI_TMS991x_ADD_NTSC(VIDEO_SYSTEM_TAG, TMS9918, 0x4000, ti99_4x_state, video_interrupt_in)
|
||||
MCFG_TI_TMS991x_ADD_NTSC(VIDEO_SYSTEM_TAG, TMS9918, 0x4000, ti99_4x_state, video_interrupt_in, gromclk_in)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/*
|
||||
European version: 50 Hz, PAL
|
||||
*/
|
||||
static MACHINE_CONFIG_DERIVED( ti99_4_50hz, ti99_4 )
|
||||
MCFG_TI_TMS991x_ADD_PAL(VIDEO_SYSTEM_TAG, TMS9929, 0x4000, ti99_4x_state, video_interrupt_in)
|
||||
MCFG_TI_TMS991x_ADD_PAL(VIDEO_SYSTEM_TAG, TMS9929, 0x4000, ti99_4x_state, video_interrupt_in, gromclk_in)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/**********************************************************************
|
||||
@ -951,9 +895,10 @@ static MACHINE_CONFIG_START( ti99_4a, ti99_4x_state )
|
||||
MCFG_TMS9901_P9_HANDLER( WRITELINE( ti99_4x_state, cassette_output) )
|
||||
MCFG_TMS9901_INTLEVEL_HANDLER( WRITE8( ti99_4x_state, tms9901_interrupt) )
|
||||
|
||||
MCFG_DMUX_ADD( DATAMUX_TAG, datamux_conf )
|
||||
MCFG_DEVICE_ADD( DATAMUX_TAG, DATAMUX, 0)
|
||||
MCFG_DMUX_READY_HANDLER( WRITELINE(ti99_4x_state, console_ready_dmux) )
|
||||
MCFG_TI99_GROMPORT_ADD( GROMPORT_TAG )
|
||||
|
||||
MCFG_GROMPORT4_ADD( GROMPORT_TAG )
|
||||
MCFG_GROMPORT_READY_HANDLER( WRITELINE(ti99_4x_state, console_ready_cart) )
|
||||
MCFG_GROMPORT_RESET_HANDLER( WRITELINE(ti99_4x_state, console_reset) )
|
||||
|
||||
@ -978,13 +923,10 @@ static MACHINE_CONFIG_START( ti99_4a, ti99_4x_state )
|
||||
MCFG_SOUND_WAVE_ADD(WAVE_TAG, "cassette")
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "cass_out", 0.25)
|
||||
|
||||
/* GROM devices */
|
||||
MCFG_GROM_ADD( GROM0_TAG, grom0_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM1_TAG, grom1_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM2_TAG, grom2_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
// GROM devices
|
||||
MCFG_GROM_ADD( GROM0_TAG, 0, region_grom, 0x0000, WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM1_TAG, 1, region_grom, 0x2000, WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM2_TAG, 2, region_grom, 0x4000, WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
|
||||
// Joystick port
|
||||
MCFG_TI_JOYPORT4A_ADD( JOYPORT_TAG )
|
||||
@ -994,14 +936,14 @@ MACHINE_CONFIG_END
|
||||
US version: 60 Hz, NTSC
|
||||
*/
|
||||
static MACHINE_CONFIG_DERIVED( ti99_4a_60hz, ti99_4a )
|
||||
MCFG_TI_TMS991x_ADD_NTSC(VIDEO_SYSTEM_TAG, TMS9918A, 0x4000, ti99_4x_state, video_interrupt_in)
|
||||
MCFG_TI_TMS991x_ADD_NTSC(VIDEO_SYSTEM_TAG, TMS9918A, 0x4000, ti99_4x_state, video_interrupt_in, gromclk_in)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/*
|
||||
European version: 50 Hz, PAL
|
||||
*/
|
||||
static MACHINE_CONFIG_DERIVED( ti99_4a_50hz, ti99_4a )
|
||||
MCFG_TI_TMS991x_ADD_PAL(VIDEO_SYSTEM_TAG, TMS9929A, 0x4000, ti99_4x_state, video_interrupt_in)
|
||||
MCFG_TI_TMS991x_ADD_PAL(VIDEO_SYSTEM_TAG, TMS9929A, 0x4000, ti99_4x_state, video_interrupt_in, gromclk_in)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/************************************************************************
|
||||
@ -1029,14 +971,14 @@ MACHINE_CONFIG_END
|
||||
US version: 60 Hz, NTSC
|
||||
*/
|
||||
static MACHINE_CONFIG_DERIVED( ti99_4qi_60hz, ti99_4qi )
|
||||
MCFG_TI_TMS991x_ADD_NTSC(VIDEO_SYSTEM_TAG, TMS9918A, 0x4000, ti99_4x_state, video_interrupt_in)
|
||||
MCFG_TI_TMS991x_ADD_NTSC(VIDEO_SYSTEM_TAG, TMS9918A, 0x4000, ti99_4x_state, video_interrupt_in, gromclk_in)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/*
|
||||
European version: 50 Hz, PAL
|
||||
*/
|
||||
static MACHINE_CONFIG_DERIVED( ti99_4qi_50hz, ti99_4qi )
|
||||
MCFG_TI_TMS991x_ADD_PAL(VIDEO_SYSTEM_TAG, TMS9929A, 0x4000, ti99_4x_state, video_interrupt_in)
|
||||
MCFG_TI_TMS991x_ADD_PAL(VIDEO_SYSTEM_TAG, TMS9929A, 0x4000, ti99_4x_state, video_interrupt_in, gromclk_in)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/************************************************************************
|
||||
@ -1056,6 +998,10 @@ static MACHINE_CONFIG_START( ti99_4ev_60hz, ti99_4x_state )
|
||||
|
||||
/* video hardware */
|
||||
MCFG_DEVICE_ADD(VIDEO_SYSTEM_TAG, V9938VIDEO, 0)
|
||||
// Removing the TMS9928a requires to add a replacement for the GROMCLK.
|
||||
// In the real hardware this is a circuit (REPL99x) that fits into the VDP socket
|
||||
MCFG_ADD_GROMCLK_CB( WRITELINE(ti99_4x_state, gromclk_in) )
|
||||
|
||||
MCFG_V9938_ADD(VDP_TAG, SCREEN_TAG, 0x20000, XTAL_21_4772MHz) /* typical 9938 clock, not verified */
|
||||
MCFG_V99X8_INTERRUPT_CALLBACK(WRITELINE(ti99_4x_state, video_interrupt_in))
|
||||
MCFG_V99X8_SCREEN_ADD_NTSC(SCREEN_TAG, VDP_TAG, XTAL_21_4772MHz)
|
||||
@ -1073,9 +1019,9 @@ static MACHINE_CONFIG_START( ti99_4ev_60hz, ti99_4x_state )
|
||||
MCFG_TMS9901_P9_HANDLER( WRITELINE( ti99_4x_state, cassette_output) )
|
||||
MCFG_TMS9901_INTLEVEL_HANDLER( WRITE8( ti99_4x_state, tms9901_interrupt) )
|
||||
|
||||
MCFG_DMUX_ADD( DATAMUX_TAG, datamux_conf_ev )
|
||||
MCFG_DEVICE_ADD( DATAMUX_TAG, DATAMUX, 0)
|
||||
MCFG_DMUX_READY_HANDLER( WRITELINE(ti99_4x_state, console_ready_dmux) )
|
||||
MCFG_TI99_GROMPORT_ADD( GROMPORT_TAG )
|
||||
MCFG_GROMPORT4_ADD( GROMPORT_TAG )
|
||||
MCFG_GROMPORT_READY_HANDLER( WRITELINE(ti99_4x_state, console_ready_cart) )
|
||||
MCFG_GROMPORT_RESET_HANDLER( WRITELINE(ti99_4x_state, console_reset) )
|
||||
|
||||
@ -1100,13 +1046,10 @@ static MACHINE_CONFIG_START( ti99_4ev_60hz, ti99_4x_state )
|
||||
MCFG_SOUND_WAVE_ADD(WAVE_TAG, "cassette")
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "cass_out", 0.25)
|
||||
|
||||
/* GROM devices */
|
||||
MCFG_GROM_ADD( GROM0_TAG, grom0_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM1_TAG, grom1_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM2_TAG, grom2_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
// GROM devices
|
||||
MCFG_GROM_ADD( GROM0_TAG, 0, region_grom, 0x0000, WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM1_TAG, 1, region_grom, 0x2000, WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM2_TAG, 2, region_grom, 0x4000, WRITELINE(ti99_4x_state, console_ready_grom))
|
||||
|
||||
// Joystick port
|
||||
MCFG_TI_JOYPORT4A_ADD( JOYPORT_TAG )
|
||||
@ -1124,7 +1067,7 @@ MACHINE_CONFIG_END
|
||||
|
||||
ROM_START(ti99_4)
|
||||
// CPU memory space
|
||||
ROM_REGION16_BE(0x2000, "maincpu", 0)
|
||||
ROM_REGION16_BE(0x2000, CONSOLEROM, 0)
|
||||
ROM_LOAD16_BYTE("u610.bin", 0x0000, 0x1000, CRC(6fcf4b15) SHA1(d085213c64701d429ae535f9a4ac8a50427a8343)) /* CPU ROMs high */
|
||||
ROM_LOAD16_BYTE("u611.bin", 0x0001, 0x1000, CRC(491c21d1) SHA1(7741ae9294c51a44a78033d1b77c01568a6bbfb9)) /* CPU ROMs low */
|
||||
|
||||
@ -1137,7 +1080,7 @@ ROM_END
|
||||
|
||||
ROM_START(ti99_4a)
|
||||
// CPU memory space
|
||||
ROM_REGION16_BE(0x2000, "maincpu", 0)
|
||||
ROM_REGION16_BE(0x2000, CONSOLEROM, 0)
|
||||
ROM_LOAD16_WORD("994arom.bin", 0x0000, 0x2000, CRC(db8f33e5) SHA1(6541705116598ab462ea9403c00656d6353ceb85)) /* system ROMs */
|
||||
|
||||
// GROM memory space
|
||||
@ -1147,7 +1090,7 @@ ROM_END
|
||||
|
||||
ROM_START(ti99_4qi)
|
||||
// CPU memory space
|
||||
ROM_REGION16_BE(0x2000, "maincpu", 0)
|
||||
ROM_REGION16_BE(0x2000, CONSOLEROM, 0)
|
||||
ROM_LOAD16_WORD("994qirom.bin", 0x0000, 0x2000, CRC(db8f33e5) SHA1(6541705116598ab462ea9403c00656d6353ceb85)) /* system ROMs */
|
||||
|
||||
// GROM memory space
|
||||
@ -1160,7 +1103,7 @@ ROM_END
|
||||
|
||||
ROM_START(ti99_4ev)
|
||||
/*CPU memory space*/
|
||||
ROM_REGION16_BE(0x2000, "maincpu", 0)
|
||||
ROM_REGION16_BE(0x2000, CONSOLEROM, 0)
|
||||
ROM_LOAD16_WORD("994arom.bin", 0x0000, 0x2000, CRC(db8f33e5) SHA1(6541705116598ab462ea9403c00656d6353ceb85)) /* system ROMs */
|
||||
|
||||
/*GROM memory space*/
|
||||
|
@ -86,33 +86,6 @@
|
||||
- Native mode (Armadillo mode): Devices are located at positions above
|
||||
0xF000 that allow for a contiguous usage of memory.
|
||||
|
||||
|
||||
ROM contents
|
||||
------------
|
||||
The ROM0 chip is accessible at addresses 0000-1FFF in the logical address
|
||||
space of the compatibility mode. It contains the GPL interpreter. In
|
||||
native mode the ROM0 chip is invisible.
|
||||
|
||||
ROM0
|
||||
offset Logical address Name
|
||||
-----------------------------------
|
||||
0000 0000-1FFF ROM0
|
||||
|
||||
|
||||
The ROM1 chip contains 32 KiB of various system software. It is located in
|
||||
the physical address space, so it must be mapped into the logical address
|
||||
space by defining an appropriate map.
|
||||
|
||||
ROM1
|
||||
offset Physical address Name
|
||||
----------------------------------------------------------
|
||||
0000 FFA000-FFDFFF ROM1
|
||||
4000 FF4000-FF5FFF @CRU>2700 Text-to-speech ROM/DSR
|
||||
6000 FF4000-FF5FFF @CRU>1700 Hexbus DSR
|
||||
|
||||
The DSR portions have to be selected via the CRU bits >1700 or >2700.
|
||||
|
||||
|
||||
Mapper
|
||||
------
|
||||
The mapper uses 4K pages (unlike the Geneve mapper with 8K pages) which
|
||||
@ -200,22 +173,27 @@ Known Issues (MZ, 2010-11-07)
|
||||
#include "emu.h"
|
||||
#include "cpu/tms9900/tms9995.h"
|
||||
|
||||
#include "bus/ti99x/ti99defs.h"
|
||||
|
||||
#include "sound/sn76496.h"
|
||||
#include "sound/wave.h"
|
||||
#include "machine/tms9901.h"
|
||||
#include "machine/tmc0430.h"
|
||||
#include "imagedev/cassette.h"
|
||||
|
||||
#include "bus/ti99x/998board.h"
|
||||
#include "bus/ti99x/videowrp.h"
|
||||
#include "bus/ti99x/grom.h"
|
||||
#include "bus/ti99x/gromport.h"
|
||||
#include "bus/ti99x/joyport.h"
|
||||
|
||||
#include "bus/ti99_peb/peribox.h"
|
||||
|
||||
#include "softlist.h"
|
||||
|
||||
// Debugging
|
||||
#define TRACE_READY 0
|
||||
#define TRACE_INTERRUPTS 0
|
||||
#define TRACE_RESET 0
|
||||
#define TRACE_CRU 0
|
||||
|
||||
/*
|
||||
@ -228,7 +206,8 @@ enum
|
||||
READY_PBOX = 4,
|
||||
READY_SOUND = 8,
|
||||
READY_CART = 16,
|
||||
READY_SPEECH = 32
|
||||
READY_SPEECH = 32,
|
||||
READY_MAINBOARD = 64
|
||||
};
|
||||
|
||||
class ti99_8_state : public driver_device
|
||||
@ -242,8 +221,7 @@ public:
|
||||
m_peribox(*this, PERIBOX_TAG),
|
||||
m_mainboard(*this, MAINBOARD8_TAG),
|
||||
m_joyport(*this, JOYPORT_TAG),
|
||||
m_video(*this, VIDEO_SYSTEM_TAG),
|
||||
m_cassette(*this, "cassette") { }
|
||||
m_cassette(*this, "cassette") { };
|
||||
|
||||
// Machine management
|
||||
DECLARE_MACHINE_START(ti99_8);
|
||||
@ -254,17 +232,17 @@ public:
|
||||
DECLARE_WRITE8_MEMBER( cruwrite );
|
||||
DECLARE_WRITE8_MEMBER( external_operation );
|
||||
DECLARE_WRITE_LINE_MEMBER( clock_out );
|
||||
DECLARE_WRITE_LINE_MEMBER( dbin_line );
|
||||
|
||||
// Connections from outside towards the CPU (callbacks)
|
||||
DECLARE_WRITE_LINE_MEMBER( console_ready_mapper );
|
||||
DECLARE_WRITE_LINE_MEMBER( console_ready_sound );
|
||||
DECLARE_WRITE_LINE_MEMBER( console_ready_pbox );
|
||||
DECLARE_WRITE_LINE_MEMBER( console_ready_cart );
|
||||
DECLARE_WRITE_LINE_MEMBER( console_ready_grom );
|
||||
DECLARE_WRITE_LINE_MEMBER( console_ready_speech );
|
||||
DECLARE_WRITE_LINE_MEMBER( console_ready );
|
||||
DECLARE_WRITE_LINE_MEMBER( console_reset );
|
||||
DECLARE_WRITE_LINE_MEMBER( cpu_hold );
|
||||
DECLARE_WRITE_LINE_MEMBER( notconnected );
|
||||
|
||||
// GROM clock (coming from Vaquerro)
|
||||
DECLARE_WRITE_LINE_MEMBER( gromclk_in );
|
||||
|
||||
// Connections with the system interface chip 9901
|
||||
DECLARE_WRITE_LINE_MEMBER( extint );
|
||||
DECLARE_WRITE_LINE_MEMBER( video_interrupt );
|
||||
@ -275,8 +253,6 @@ public:
|
||||
DECLARE_WRITE_LINE_MEMBER(keyC1);
|
||||
DECLARE_WRITE_LINE_MEMBER(keyC2);
|
||||
DECLARE_WRITE_LINE_MEMBER(keyC3);
|
||||
DECLARE_WRITE_LINE_MEMBER(CRUS);
|
||||
DECLARE_WRITE_LINE_MEMBER(PTGEN);
|
||||
DECLARE_WRITE_LINE_MEMBER(audio_gate);
|
||||
DECLARE_WRITE_LINE_MEMBER(cassette_output);
|
||||
DECLARE_WRITE_LINE_MEMBER(cassette_motor);
|
||||
@ -288,9 +264,7 @@ private:
|
||||
int m_keyboard_column;
|
||||
|
||||
// READY handling
|
||||
int m_nready_combined;
|
||||
int m_nready_prev;
|
||||
void console_ready_join(int id, int state);
|
||||
line_state m_ready_old;
|
||||
|
||||
// Latch for 9901 INT2, INT1 lines
|
||||
line_state m_int1;
|
||||
@ -303,7 +277,6 @@ private:
|
||||
required_device<peribox_device> m_peribox;
|
||||
required_device<mainboard8_device> m_mainboard;
|
||||
required_device<joyport_device> m_joyport;
|
||||
required_device<ti_video_device> m_video;
|
||||
required_device<cassette_image_device> m_cassette;
|
||||
};
|
||||
|
||||
@ -312,7 +285,7 @@ private:
|
||||
job to the mapper completely.
|
||||
*/
|
||||
static ADDRESS_MAP_START(memmap, AS_PROGRAM, 8, ti99_8_state)
|
||||
AM_RANGE(0x0000, 0xffff) AM_DEVREADWRITE(MAINBOARD8_TAG, mainboard8_device, readm, writem )
|
||||
AM_RANGE(0x0000, 0xffff) AM_DEVREADWRITE(MAINBOARD8_TAG, mainboard8_device, read, write) AM_DEVSETOFFSET(MAINBOARD8_TAG, mainboard8_device, setoffset)
|
||||
ADDRESS_MAP_END
|
||||
|
||||
/*
|
||||
@ -432,89 +405,6 @@ static INPUT_PORTS_START(ti99_8)
|
||||
|
||||
INPUT_PORTS_END
|
||||
|
||||
/*****************************************************************************
|
||||
Components
|
||||
******************************************************************************/
|
||||
#define region_sysgrom "sysgrom"
|
||||
|
||||
static GROM_CONFIG(grom0_config)
|
||||
{
|
||||
false, 0, region_sysgrom, 0x0000, 0x1800, GROMFREQ
|
||||
};
|
||||
|
||||
static GROM_CONFIG(grom1_config)
|
||||
{
|
||||
false, 1, region_sysgrom, 0x2000, 0x1800, GROMFREQ
|
||||
};
|
||||
|
||||
static GROM_CONFIG(grom2_config)
|
||||
{
|
||||
false, 2, region_sysgrom, 0x4000, 0x1800, GROMFREQ
|
||||
};
|
||||
|
||||
/****************************************************
|
||||
PASCAL groms, 3 libraries @ 8 GROMs
|
||||
Do some macro tricks to keep writing effort low
|
||||
*****************************************************/
|
||||
|
||||
#define region_gromlib1 "gromlib1"
|
||||
#define region_gromlib2 "gromlib2"
|
||||
#define region_gromlib3 "gromlib3"
|
||||
|
||||
#define MCFG_GROM_LIBRARY_ADD8(_tag, _config) \
|
||||
MCFG_DEVICE_ADD(#_tag "0", GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config##0) \
|
||||
MCFG_DEVICE_ADD(#_tag "1", GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config##1) \
|
||||
MCFG_DEVICE_ADD(#_tag "2", GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config##2) \
|
||||
MCFG_DEVICE_ADD(#_tag "3", GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config##3) \
|
||||
MCFG_DEVICE_ADD(#_tag "4", GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config##4) \
|
||||
MCFG_DEVICE_ADD(#_tag "5", GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config##5) \
|
||||
MCFG_DEVICE_ADD(#_tag "6", GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config##6) \
|
||||
MCFG_DEVICE_ADD(#_tag "7", GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config##7)
|
||||
|
||||
#define MCFG_GROM_LIBRARY_ADD3(_tag, _config) \
|
||||
MCFG_DEVICE_ADD(#_tag "0", GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config##0) \
|
||||
MCFG_DEVICE_ADD(#_tag "1", GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config##1) \
|
||||
MCFG_DEVICE_ADD(#_tag "2", GROM, 0) \
|
||||
MCFG_DEVICE_CONFIG(_config##2)
|
||||
|
||||
#define GROM_LIBRARY_CONFIG8(_conf, _region) \
|
||||
static GROM_CONFIG(_conf##0) \
|
||||
{ false, 0, _region, 0x0000, 0x1800, GROMFREQ }; \
|
||||
static GROM_CONFIG(_conf##1) \
|
||||
{ false, 1, _region, 0x2000, 0x1800, GROMFREQ }; \
|
||||
static GROM_CONFIG(_conf##2) \
|
||||
{ false, 2, _region, 0x4000, 0x1800, GROMFREQ }; \
|
||||
static GROM_CONFIG(_conf##3) \
|
||||
{ false, 3, _region, 0x6000, 0x1800, GROMFREQ }; \
|
||||
static GROM_CONFIG(_conf##4) \
|
||||
{ false, 4, _region, 0x8000, 0x1800, GROMFREQ }; \
|
||||
static GROM_CONFIG(_conf##5) \
|
||||
{ false, 5, _region, 0xa000, 0x1800, GROMFREQ }; \
|
||||
static GROM_CONFIG(_conf##6) \
|
||||
{ false, 6, _region, 0xc000, 0x1800, GROMFREQ }; \
|
||||
static GROM_CONFIG(_conf##7) \
|
||||
{ false, 7, _region, 0xe000, 0x1800, GROMFREQ };
|
||||
|
||||
#define GROM_LIBRARY_CONFIG3(_conf, _region) \
|
||||
static GROM_CONFIG(_conf##0) \
|
||||
{ false, 0, _region, 0x0000, 0x1800, GROMFREQ }; \
|
||||
static GROM_CONFIG(_conf##1) \
|
||||
{ false, 1, _region, 0x2000, 0x1800, GROMFREQ }; \
|
||||
static GROM_CONFIG(_conf##2) \
|
||||
{ false, 2, _region, 0x4000, 0x1800, GROMFREQ };
|
||||
GROM_LIBRARY_CONFIG8(pascal1, region_gromlib1)
|
||||
GROM_LIBRARY_CONFIG8(pascal2, region_gromlib2)
|
||||
GROM_LIBRARY_CONFIG3(pascal3, region_gromlib3)
|
||||
|
||||
READ8_MEMBER( ti99_8_state::cruread )
|
||||
{
|
||||
@ -660,33 +550,6 @@ WRITE_LINE_MEMBER( ti99_8_state::keyC3 )
|
||||
set_keyboard_column(3, state);
|
||||
}
|
||||
|
||||
/*
|
||||
Set 99/4A compatibility mode (CRUS=1)
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_8_state::CRUS )
|
||||
{
|
||||
m_mainboard->CRUS_set(state==ASSERT_LINE);
|
||||
|
||||
// In Armadillo mode, GROMs are located at f830; accordingly, the
|
||||
// gromport must be reconfigured
|
||||
if (state==ASSERT_LINE)
|
||||
{
|
||||
m_gromport->set_grom_base(0x9800, 0xfbf1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gromport->set_grom_base(0xf830, 0xfff1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Set mapper /PTGEN. This is negative logic; we use PTGE as the positive logic signal.
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_8_state::PTGEN )
|
||||
{
|
||||
m_mainboard->PTGE_set(state==CLEAR_LINE);
|
||||
}
|
||||
|
||||
/*
|
||||
Control cassette tape unit motor (P6)
|
||||
*/
|
||||
@ -723,11 +586,11 @@ WRITE8_MEMBER( ti99_8_state::tms9901_interrupt )
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
set the state of TMS9901's INT2 (called by the tms9928 core)
|
||||
set the state of TMS9901's INT2 (called by the VDP)
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_8_state::video_interrupt )
|
||||
{
|
||||
if (TRACE_INTERRUPTS) logerror("ti99_8: VDP int 2 on tms9901, level=%02x\n", state);
|
||||
if (TRACE_INTERRUPTS) logerror("VDP int 2 on tms9901, level=%02x\n", state);
|
||||
m_int2 = (line_state)state;
|
||||
m_tms9901->set_single_int(2, state);
|
||||
}
|
||||
@ -737,82 +600,59 @@ WRITE_LINE_MEMBER( ti99_8_state::video_interrupt )
|
||||
***********************************************************/
|
||||
|
||||
/*
|
||||
We combine the incoming READY signals and propagate them to the CPU.
|
||||
An alternative would be to let the CPU get the READY state, but this would
|
||||
be a much higher overhead, as this happens in each clock tick.
|
||||
Propagate READY signals to the CPU.
|
||||
*/
|
||||
void ti99_8_state::console_ready_join(int id, int state)
|
||||
void ti99_8_state::console_ready(int state)
|
||||
{
|
||||
if (state==CLEAR_LINE)
|
||||
m_nready_combined |= id;
|
||||
else
|
||||
m_nready_combined &= ~id;
|
||||
|
||||
if (TRACE_READY)
|
||||
{
|
||||
if (m_nready_prev != m_nready_combined) logerror("ti99_8: READY bits = %04x\n", ~m_nready_combined);
|
||||
if (m_ready_old != state) logerror("READY = %d\n", state);
|
||||
}
|
||||
|
||||
m_nready_prev = m_nready_combined;
|
||||
m_cpu->ready_line(m_nready_combined==0);
|
||||
m_ready_old = (line_state)state;
|
||||
m_cpu->ready_line(state);
|
||||
}
|
||||
|
||||
/*
|
||||
Connections to the READY line. This might look a bit ugly; we need an
|
||||
implementation of a "Wired AND" device.
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_8_state::console_ready_grom )
|
||||
{
|
||||
console_ready_join(READY_GROM, state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_8_state::console_ready_mapper )
|
||||
{
|
||||
console_ready_join(READY_MAPPER, state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_8_state::console_ready_pbox )
|
||||
{
|
||||
console_ready_join(READY_PBOX, state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_8_state::console_ready_sound )
|
||||
{
|
||||
console_ready_join(READY_SOUND, state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_8_state::console_ready_cart )
|
||||
{
|
||||
console_ready_join(READY_CART, state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_8_state::console_ready_speech )
|
||||
{
|
||||
console_ready_join(READY_SPEECH, state);
|
||||
}
|
||||
|
||||
/*
|
||||
The RESET line leading to a reset of the CPU.
|
||||
Enqueue a RESET signal.
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_8_state::console_reset )
|
||||
{
|
||||
if (TRACE_RESET) logerror("Incoming RESET line = %d\n", state);
|
||||
if (machine().phase() != MACHINE_PHASE_INIT)
|
||||
{
|
||||
m_cpu->set_input_line(INT_9995_RESET, state);
|
||||
m_video->reset_vdp(state);
|
||||
// RESET the 9901
|
||||
m_tms9901->rst1_line(state);
|
||||
|
||||
// Pull up the CRUS and PTGEN lines (9901 outputs have been deactivated, pull-up resistors on the board show effect)
|
||||
m_mainboard->crus_in(TRUE); // assert
|
||||
m_mainboard->ptgen_in(TRUE); // clear
|
||||
|
||||
// Setting ready to false so that automatic wait states are enabled
|
||||
m_cpu->ready_line(CLEAR_LINE);
|
||||
m_cpu->reset_line(ASSERT_LINE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The HOLD line leading to the CPU entering the HOLD state.
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_8_state::cpu_hold )
|
||||
{
|
||||
if (TRACE_INTERRUPTS) logerror("Incoming HOLD line = %d\n", state);
|
||||
m_cpu->hold_line(state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_8_state::extint )
|
||||
{
|
||||
if (TRACE_READY) logerror("ti99_8: EXTINT level = %02x\n", state);
|
||||
if (TRACE_INTERRUPTS) logerror("EXTINT level = %02x\n", state);
|
||||
m_int1 = (line_state)state;
|
||||
m_tms9901->set_single_int(1, state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_8_state::notconnected )
|
||||
{
|
||||
if (TRACE_READY) logerror("ti99_8: Setting a not connected line ... ignored\n");
|
||||
if (TRACE_INTERRUPTS) logerror("Setting a not connected line ... ignored\n");
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( ti99_8_state::external_operation )
|
||||
@ -821,7 +661,7 @@ WRITE8_MEMBER( ti99_8_state::external_operation )
|
||||
if (offset == IDLE_OP) return;
|
||||
else
|
||||
{
|
||||
logerror("ti99_4x: External operation %s not implemented on TI-99/8 board\n", extop[offset]);
|
||||
logerror("External operation %s not implemented on TI-99/8 board\n", extop[offset]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -833,119 +673,23 @@ WRITE_LINE_MEMBER( ti99_8_state::clock_out )
|
||||
m_mainboard->clock_in(state);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
Format:
|
||||
Name, mode, stop, mask, select, write, read8z function, write8 function
|
||||
|
||||
Multiple devices may have the same select pattern; as in the real hardware,
|
||||
care must be taken that only one device actually responds. In the case of
|
||||
GROMs, each chip has an internal address counter and an ID, and the chip
|
||||
only responds when the ID and the most significant 3 bits match.
|
||||
|
||||
NATIVE <-> CRUS=0
|
||||
TI99EM <-> CRUS=1
|
||||
|
||||
PATGEN <-> PTGEN=1
|
||||
|
||||
CONT: Mapper continues iterating through devices
|
||||
STOP: Mapper stops iterating when found
|
||||
|
||||
Access to the mapper registers is done directly in the mapper, not via
|
||||
this list.
|
||||
|
||||
TODO: This should (must) be improved in terms of performance. Every single
|
||||
memory access goes through the mapper. Either we use an ordered search list,
|
||||
or we order the entries according to their frequency.
|
||||
(I did this right now, putting the Pascal GROMs at the end.)
|
||||
We should think about a set entry where devices with the same address
|
||||
are collected as one single entry (think about the Pascal lib with 21 GROMs,
|
||||
twice eight and once three of them on the same address).
|
||||
Data bus in (DBIN) line from the CPU.
|
||||
*/
|
||||
|
||||
#define PASCAL_GROM_LIB8(_tag, _addr) \
|
||||
{ _tag "0", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \
|
||||
{ _tag "1", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \
|
||||
{ _tag "2", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \
|
||||
{ _tag "3", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \
|
||||
{ _tag "4", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \
|
||||
{ _tag "5", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \
|
||||
{ _tag "6", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \
|
||||
{ _tag "7", PATGEN, CONT, _addr, 0xfff1, 0x0000 }
|
||||
|
||||
#define PASCAL_GROM_LIB3(_tag, _addr) \
|
||||
{ _tag "0", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \
|
||||
{ _tag "1", PATGEN, CONT, _addr, 0xfff1, 0x0000 }, \
|
||||
{ _tag "2", PATGEN, CONT, _addr, 0xfff1, 0x0000 }
|
||||
|
||||
|
||||
static const mapper8_list_entry mapper_devices[] =
|
||||
WRITE_LINE_MEMBER( ti99_8_state::dbin_line )
|
||||
{
|
||||
// TI-99/4A mode (CRUS=1)
|
||||
// Full/partial decoding has been verified on a real machine
|
||||
// GROMs: According to the spec, the 99/8 supports up to 4 GROM libraries
|
||||
// (99/4A supports 256 libraries)
|
||||
// at 9800, 9804, 9808, 980c. Address counter access is at 9802,6,a,e. Write access +0400.
|
||||
{ ROM0NAME, TI99EM, STOP, 0x0000, 0xe000, 0x0000 }, // 0000-1fff
|
||||
{ TISOUND_TAG, TI99EM, STOP, 0x8400, 0xfff1, 0x0000 }, // 8400-840f
|
||||
{ VIDEO_SYSTEM_TAG, TI99EM, STOP, 0x8800, 0xfff1, 0x0400 }, // 8800,8802 / 8c00,8c02
|
||||
{ SPEECH_TAG, TI99EM, STOP, 0x9000, 0xfff1, 0x0400 }, // 9000-900f / 9400-940f
|
||||
{ SRAMNAME, TI99EM, STOP, 0x8000, 0xf800, 0x0000 }, // 8000-87ff; must follow the sound generator
|
||||
{ MAINBOARD8_TAG, TI99EM, STOP, 0x8810, 0xfff0, 0x0000 },
|
||||
|
||||
{ GROM0_TAG, TI99EM, CONT, 0x9800, 0xfff1, 0x0400 }, // 9800,2,4,...e/9c00,2,4,...e
|
||||
{ GROM1_TAG, TI99EM, CONT, 0x9800, 0xfff1, 0x0400 }, // dto.
|
||||
{ GROM2_TAG, TI99EM, CONT, 0x9800, 0xfff1, 0x0400 }, // dto. (GROMs are connected in parallel,
|
||||
{ GROMPORT_TAG, TI99EM, CONT, 0x9800, 0xfff1, 0x0400 }, // dto. use internal address counter and id)
|
||||
|
||||
// TI-99/8 mode
|
||||
// Full/partial decoding has been verified on a real machine
|
||||
// Sound ports are at f800, f802, f804, ..., f80e
|
||||
// VDP ports are (f810,f812), (f814,f816), (f818,f81a), (f81c,f81e)
|
||||
// Note that unmapped GROM accesses (odd addresses like F831) return FF,
|
||||
// not 00 as in our emulation, so that is not quite consistent, but tolerable ... I guess
|
||||
|
||||
{ SRAMNAME, NATIVE, STOP, 0xf000, 0xf800, 0x0000 }, // f000-f7ff
|
||||
{ TISOUND_TAG, NATIVE, STOP, 0xf800, 0xfff1, 0x0000 }, // f800-f80e (even addresses)
|
||||
{ VIDEO_SYSTEM_TAG, NATIVE, STOP, 0xf810, 0xfff1, 0x0000 }, // f810,2 (unlike 99/4A, no different read/write ports)
|
||||
{ SPEECH_TAG, NATIVE, STOP, 0xf820, 0xfff1, 0x0000 }, // f820-f82f
|
||||
{ MAINBOARD8_TAG, NATIVE, STOP, 0xf870, 0xfff0, 0x0000 },
|
||||
|
||||
{ GROM0_TAG, NATIVE, CONT, 0xf830, 0xfff1, 0x0000 }, // f830-f83e (4 banks), no different read/write ports
|
||||
{ GROM1_TAG, NATIVE, CONT, 0xf830, 0xfff1, 0x0000 },
|
||||
{ GROM2_TAG, NATIVE, CONT, 0xf830, 0xfff1, 0x0000 },
|
||||
{ GROMPORT_TAG, NATIVE, CONT, 0xf830, 0xfff1, 0x0000 },
|
||||
|
||||
PASCAL_GROM_LIB8("pascal1_grom", 0xf840),
|
||||
PASCAL_GROM_LIB8("pascal2_grom", 0xf850),
|
||||
PASCAL_GROM_LIB3("pascal3_grom", 0xf860),
|
||||
|
||||
// Physical (need to pack this in here as well to keep config simple)
|
||||
// but these lines will be put into a separate list
|
||||
{ DRAMNAME, PHYSIC, STOP, 0x000000, 0xff0000, 0x000000 }, // 000000-00ffff 64 KiB DRAM
|
||||
{ PCODENAME, PHYSIC, STOP, 0xf00000, 0xffc000, 0x000000 }, // f00000-f03fff P-Code ROM
|
||||
{ MAINBOARD8_TAG, PHYSIC, CONT, 0xff4000, 0xffe000, 0x000000 }, // ff4000-ff5fff Internal DSR
|
||||
{ GROMPORT_TAG, PHYSIC, STOP, 0xff6000, 0xffe000, 0x000000 }, // ff6000-ff7fff Cartridge ROM space
|
||||
{ GROMPORT_TAG, PHYSIC, STOP, 0xff8000, 0xffe000, 0x000000 }, // ff8000-ff9fff Cartridge ROM space
|
||||
{ ROM1A0NAME, PHYSIC, STOP, 0xffa000, 0xffe000, 0x000000 }, // ffa000-ffbfff ROM1
|
||||
{ ROM1C0NAME, PHYSIC, STOP, 0xffc000, 0xffe000, 0x000000 }, // ffc000-ffdfff ROM1
|
||||
{ INTSNAME, PHYSIC, STOP, 0xffe000, 0xfffff0, 0x000000 }, // ffe000-ffe00f Interrupt level sense
|
||||
{ PERIBOX_TAG, PHYSIC, STOP, 0x000000, 0x000000, 0x000000 }, // Peripheral Expansion Box
|
||||
|
||||
{ nullptr, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
static MAPPER8_CONFIG( mapper_conf )
|
||||
{
|
||||
mapper_devices
|
||||
};
|
||||
m_mainboard->dbin_in(state);
|
||||
}
|
||||
|
||||
MACHINE_START_MEMBER(ti99_8_state,ti99_8)
|
||||
{
|
||||
m_nready_combined = 0;
|
||||
m_peribox->senila(CLEAR_LINE);
|
||||
m_peribox->senilb(CLEAR_LINE);
|
||||
// m_mainboard->set_gromport(m_gromport);
|
||||
|
||||
// Need to configure the speech ROM for inverse bit order
|
||||
speechrom_device* mem = subdevice<speechrom_device>(SPEECHROM_REG);
|
||||
mem->set_reverse_bit_order(true);
|
||||
}
|
||||
|
||||
MACHINE_RESET_MEMBER(ti99_8_state, ti99_8)
|
||||
@ -956,9 +700,7 @@ MACHINE_RESET_MEMBER(ti99_8_state, ti99_8)
|
||||
// state on external memory accesses
|
||||
m_cpu->ready_line(CLEAR_LINE);
|
||||
|
||||
// But we assert the line here so that the system starts running
|
||||
m_nready_combined = 0;
|
||||
m_gromport->set_grom_base(0x9800, 0xfff1);
|
||||
// m_gromport->set_grom_base(0x9800, 0xfff1);
|
||||
|
||||
// Clear INT1 and INT2 latch
|
||||
m_int1 = CLEAR_LINE;
|
||||
@ -972,62 +714,92 @@ static MACHINE_CONFIG_START( ti99_8, ti99_8_state )
|
||||
MCFG_TMS99xx_ADD("maincpu", TMS9995_MP9537, XTAL_10_738635MHz, memmap, crumap)
|
||||
MCFG_TMS9995_EXTOP_HANDLER( WRITE8(ti99_8_state, external_operation) )
|
||||
MCFG_TMS9995_CLKOUT_HANDLER( WRITELINE(ti99_8_state, clock_out) )
|
||||
MCFG_TMS9995_DBIN_HANDLER( WRITELINE(ti99_8_state, dbin_line) )
|
||||
MCFG_TMS9995_HOLDA_HANDLER( DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, holda_line) )
|
||||
|
||||
MCFG_MACHINE_START_OVERRIDE(ti99_8_state, ti99_8 )
|
||||
MCFG_MACHINE_RESET_OVERRIDE(ti99_8_state, ti99_8 )
|
||||
|
||||
/* Main board */
|
||||
// 9901 configuration
|
||||
MCFG_DEVICE_ADD(TMS9901_TAG, TMS9901, XTAL_10_738635MHz/4.0)
|
||||
MCFG_TMS9901_READBLOCK_HANDLER( READ8(ti99_8_state, read_by_9901) )
|
||||
MCFG_TMS9901_P0_HANDLER( WRITELINE( ti99_8_state, keyC0) )
|
||||
MCFG_TMS9901_P1_HANDLER( WRITELINE( ti99_8_state, keyC1) )
|
||||
MCFG_TMS9901_P2_HANDLER( WRITELINE( ti99_8_state, keyC2) )
|
||||
MCFG_TMS9901_P3_HANDLER( WRITELINE( ti99_8_state, keyC3) )
|
||||
MCFG_TMS9901_P4_HANDLER( WRITELINE( ti99_8_state, CRUS) )
|
||||
MCFG_TMS9901_P5_HANDLER( WRITELINE( ti99_8_state, PTGEN) )
|
||||
MCFG_TMS9901_P4_HANDLER( DEVWRITELINE( MAINBOARD8_TAG, mainboard8_device, crus_in) )
|
||||
MCFG_TMS9901_P5_HANDLER( DEVWRITELINE( MAINBOARD8_TAG, mainboard8_device, ptgen_in) )
|
||||
MCFG_TMS9901_P6_HANDLER( WRITELINE( ti99_8_state, cassette_motor) )
|
||||
MCFG_TMS9901_P8_HANDLER( WRITELINE( ti99_8_state, audio_gate) )
|
||||
MCFG_TMS9901_P9_HANDLER( WRITELINE( ti99_8_state, cassette_output) )
|
||||
MCFG_TMS9901_INTLEVEL_HANDLER( WRITE8( ti99_8_state, tms9901_interrupt) )
|
||||
|
||||
MCFG_MAINBOARD8_ADD( MAINBOARD8_TAG, mapper_conf )
|
||||
MCFG_MAINBOARD8_READY_CALLBACK(WRITELINE(ti99_8_state, console_ready_mapper))
|
||||
MCFG_TI99_GROMPORT_ADD( GROMPORT_TAG )
|
||||
MCFG_GROMPORT_READY_HANDLER( WRITELINE(ti99_8_state, console_ready_cart) )
|
||||
// Mainboard with custom chips
|
||||
MCFG_DEVICE_ADD(MAINBOARD8_TAG, MAINBOARD8, 0)
|
||||
MCFG_MAINBOARD8_READY_CALLBACK(WRITELINE(ti99_8_state, console_ready))
|
||||
MCFG_MAINBOARD8_RESET_CALLBACK(WRITELINE(ti99_8_state, console_reset))
|
||||
MCFG_MAINBOARD8_HOLD_CALLBACK(WRITELINE(ti99_8_state, cpu_hold))
|
||||
|
||||
MCFG_GROMPORT8_ADD( GROMPORT_TAG )
|
||||
MCFG_GROMPORT_READY_HANDLER( DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, system_grom_ready) )
|
||||
MCFG_GROMPORT_RESET_HANDLER( WRITELINE(ti99_8_state, console_reset) )
|
||||
|
||||
/* Peripheral expansion box */
|
||||
/* Software list */
|
||||
MCFG_SOFTWARE_LIST_ADD("cart_list_ti99", "ti99_cart")
|
||||
|
||||
// Peripheral expansion box
|
||||
MCFG_DEVICE_ADD( PERIBOX_TAG, PERIBOX_998, 0)
|
||||
MCFG_PERIBOX_INTA_HANDLER( WRITELINE(ti99_8_state, extint) )
|
||||
MCFG_PERIBOX_INTB_HANDLER( WRITELINE(ti99_8_state, notconnected) )
|
||||
MCFG_PERIBOX_READY_HANDLER( WRITELINE(ti99_8_state, console_ready_pbox) )
|
||||
MCFG_PERIBOX_READY_HANDLER( DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, pbox_ready) )
|
||||
|
||||
/* Sound hardware */
|
||||
MCFG_TI_SOUND_76496_ADD( TISOUND_TAG )
|
||||
MCFG_TI_SOUND_READY_HANDLER( WRITELINE(ti99_8_state, console_ready_sound) )
|
||||
// Sound hardware
|
||||
MCFG_SPEAKER_STANDARD_MONO("sound_out")
|
||||
MCFG_SOUND_ADD(TISOUNDCHIP_TAG, SN76496, 3579545) /* 3.579545 MHz */
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "sound_out", 0.75)
|
||||
MCFG_SN76496_READY_HANDLER(DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, sound_ready))
|
||||
|
||||
/* Cassette drives */
|
||||
// Speech hardware
|
||||
// Note: SPEECHROM uses its tag for referencing the region
|
||||
MCFG_DEVICE_ADD(SPEECHROM_REG, SPEECHROM, 0)
|
||||
MCFG_SPEAKER_STANDARD_MONO("speech_out")
|
||||
MCFG_SOUND_ADD(SPEECHSYN_TAG, CD2501ECD, 640000L)
|
||||
MCFG_TMS52XX_READYQ_HANDLER(DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, speech_ready))
|
||||
MCFG_TMS52XX_SPEECHROM(SPEECHROM_REG)
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "speech_out", 0.50)
|
||||
|
||||
// Cassette drive
|
||||
MCFG_SPEAKER_STANDARD_MONO("cass_out")
|
||||
MCFG_CASSETTE_ADD( "cassette" )
|
||||
MCFG_SOUND_WAVE_ADD(WAVE_TAG, "cassette")
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "cass_out", 0.25)
|
||||
|
||||
/* Console GROMs */
|
||||
MCFG_GROM_ADD( GROM0_TAG, grom0_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_8_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM1_TAG, grom1_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_8_state, console_ready_grom))
|
||||
MCFG_GROM_ADD( GROM2_TAG, grom2_config )
|
||||
MCFG_GROM_READY_CALLBACK(WRITELINE(ti99_8_state, console_ready_grom))
|
||||
// GROM library
|
||||
MCFG_GROM_ADD( SYSGROM0_TAG, 0, SYSGROM_REG, 0x0000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, system_grom_ready))
|
||||
MCFG_GROM_ADD( SYSGROM1_TAG, 1, SYSGROM_REG, 0x2000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, system_grom_ready))
|
||||
MCFG_GROM_ADD( SYSGROM2_TAG, 2, SYSGROM_REG, 0x4000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, system_grom_ready))
|
||||
|
||||
/* Pascal GROM libraries. */
|
||||
MCFG_GROM_LIBRARY_ADD8(pascal1_grom, pascal1)
|
||||
MCFG_GROM_LIBRARY_ADD8(pascal2_grom, pascal2)
|
||||
MCFG_GROM_LIBRARY_ADD3(pascal3_grom, pascal3)
|
||||
MCFG_GROM_ADD( GLIB10_TAG, 0, GROMLIB1_REG, 0x0000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, ptts_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB11_TAG, 1, GROMLIB1_REG, 0x2000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, ptts_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB12_TAG, 2, GROMLIB1_REG, 0x4000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, ptts_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB13_TAG, 3, GROMLIB1_REG, 0x6000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, ptts_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB14_TAG, 4, GROMLIB1_REG, 0x8000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, ptts_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB15_TAG, 5, GROMLIB1_REG, 0xa000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, ptts_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB16_TAG, 6, GROMLIB1_REG, 0xc000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, ptts_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB17_TAG, 7, GROMLIB1_REG, 0xe000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, ptts_grom_ready))
|
||||
|
||||
/* Devices */
|
||||
MCFG_DEVICE_ADD(SPEECH_TAG, SPEECH8, 0)
|
||||
MCFG_SPEECH8_READY_CALLBACK(WRITELINE(ti99_8_state, console_ready_speech))
|
||||
MCFG_GROM_ADD( GLIB20_TAG, 0, GROMLIB2_REG, 0x0000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, p8_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB21_TAG, 1, GROMLIB2_REG, 0x2000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, p8_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB22_TAG, 2, GROMLIB2_REG, 0x4000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, p8_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB23_TAG, 3, GROMLIB2_REG, 0x6000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, p8_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB24_TAG, 4, GROMLIB2_REG, 0x8000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, p8_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB25_TAG, 5, GROMLIB2_REG, 0xa000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, p8_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB26_TAG, 6, GROMLIB2_REG, 0xc000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, p8_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB27_TAG, 7, GROMLIB2_REG, 0xe000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, p8_grom_ready))
|
||||
|
||||
MCFG_GROM_ADD( GLIB30_TAG, 0, GROMLIB3_REG, 0x0000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, p3_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB31_TAG, 1, GROMLIB3_REG, 0x2000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, p3_grom_ready))
|
||||
MCFG_GROM_ADD( GLIB32_TAG, 2, GROMLIB3_REG, 0x4000, DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, p3_grom_ready))
|
||||
|
||||
// Joystick port
|
||||
MCFG_TI_JOYPORT4A_ADD( JOYPORT_TAG )
|
||||
@ -1037,14 +809,24 @@ MACHINE_CONFIG_END
|
||||
TI-99/8 US version (NTSC, 60 Hz)
|
||||
*/
|
||||
static MACHINE_CONFIG_DERIVED( ti99_8_60hz, ti99_8 )
|
||||
MCFG_TI998_ADD_NTSC(VIDEO_SYSTEM_TAG, TMS9118, 0x4000, ti99_8_state, video_interrupt)
|
||||
// Video hardware
|
||||
MCFG_DEVICE_ADD( VDP_TAG, TMS9118, XTAL_10_738635MHz / 2 )
|
||||
MCFG_TMS9928A_VRAM_SIZE(0x4000)
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(ti99_8_state, video_interrupt))
|
||||
MCFG_TMS9928A_SCREEN_ADD_NTSC( SCREEN_TAG )
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/*
|
||||
TI-99/8 European version (PAL, 50 Hz)
|
||||
*/
|
||||
static MACHINE_CONFIG_DERIVED( ti99_8_50hz, ti99_8 )
|
||||
MCFG_TI998_ADD_PAL(VIDEO_SYSTEM_TAG, TMS9129, 0x4000, ti99_8_state, video_interrupt)
|
||||
// Video hardware
|
||||
MCFG_DEVICE_ADD( VDP_TAG, TMS9129, XTAL_10_738635MHz / 2 )
|
||||
MCFG_TMS9928A_VRAM_SIZE(0x4000)
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(ti99_8_state,video_interrupt))
|
||||
MCFG_TMS9928A_SCREEN_ADD_PAL( SCREEN_TAG )
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/*
|
||||
@ -1055,11 +837,11 @@ MACHINE_CONFIG_END
|
||||
*/
|
||||
ROM_START(ti99_8)
|
||||
// Logical (CPU) memory space: ROM0
|
||||
ROM_REGION(0x2000, ROM0_TAG, 0)
|
||||
ROM_REGION(0x2000, ROM0_REG, 0)
|
||||
ROM_LOAD("u4_rom0.bin", 0x0000, 0x2000, CRC(901eb8d6) SHA1(13190c5e834baa9c0a70066b566cfcef438ed88a))
|
||||
|
||||
// Physical memory space (mapped): ROM1
|
||||
ROM_REGION(0x8000, ROM1_TAG, 0)
|
||||
ROM_REGION(0x8000, ROM1_REG, 0)
|
||||
ROM_LOAD("u25_rom1.bin", 0x0000, 0x8000, CRC(b574461a) SHA1(42c6aed44802cfabdd26b565d6e5ddfcd689f11e))
|
||||
|
||||
// Physical memory space (mapped): P-Code ROM
|
||||
@ -1069,20 +851,20 @@ ROM_START(ti99_8)
|
||||
// the required select line for this ROM on the available schematics, so
|
||||
// they seem to be from the earlier version. The location in the address
|
||||
// space was determined by ROM disassembly.
|
||||
ROM_REGION(0x8000, PCODEROM_TAG, 0)
|
||||
ROM_REGION(0x8000, PASCAL_REG, 0)
|
||||
ROM_LOAD("u25a_pas.bin", 0x0000, 0x4000, CRC(d7ed6dd6) SHA1(32212ce6426ceccbff73d342d4a3ef699c0ae1e4))
|
||||
|
||||
// System GROMs. 3 chips @ f830
|
||||
// The schematics do not enumerate the circuits but only talk about
|
||||
// "circuits on board" (COB) so we name the GROMs as gM_N.bin where M is the
|
||||
// ID (0-7) and N is the access port in the logical address space.
|
||||
ROM_REGION(0x6000, region_sysgrom, 0)
|
||||
ROM_REGION(0x6000, SYSGROM_REG, 0)
|
||||
ROM_LOAD("g0_f830.bin", 0x0000, 0x1800, CRC(1026db60) SHA1(7327095bf4f390476e69d9fd8424e98ea1f2325a))
|
||||
ROM_LOAD("g1_f830.bin", 0x2000, 0x1800, CRC(93a43d65) SHA1(19be8a07d674bc7554c2bc9c7a5725d81e888e6e))
|
||||
ROM_LOAD("g2_f830.bin", 0x4000, 0x1800, CRC(06f2b901) SHA1(f65e0fcb2c63e230b4a9563c72f91259b94ce955))
|
||||
|
||||
// TTS & Pascal library. 8 chips @ f840
|
||||
ROM_REGION(0x10000, region_gromlib1, 0)
|
||||
ROM_REGION(0x10000, GROMLIB1_REG, 0)
|
||||
ROM_LOAD("g0_f840.bin", 0x0000, 0x1800, CRC(44501071) SHA1(4b5ef7f1aa43a87e7ae4f02090944be5c39b1f26))
|
||||
ROM_LOAD("g1_f840.bin", 0x2000, 0x1800, CRC(5a271d9e) SHA1(bb95befa2ffba2cc17ac437386e069e8ff621248))
|
||||
ROM_LOAD("g2_f840.bin", 0x4000, 0x1800, CRC(d52502df) SHA1(17063e33ee8709d0df8030f38bb92c4322d55e1e))
|
||||
@ -1093,7 +875,7 @@ ROM_START(ti99_8)
|
||||
ROM_LOAD("g7_f840.bin", 0xE000, 0x1800, CRC(3a9d20df) SHA1(1e6f9f8ec7df4b997a7579be742d0a7d54bc8763))
|
||||
|
||||
// Pascal library. 8 chips @ f850
|
||||
ROM_REGION(0x10000, region_gromlib2, 0)
|
||||
ROM_REGION(0x10000, GROMLIB2_REG, 0)
|
||||
ROM_LOAD("g0_f850.bin", 0x0000, 0x1800, CRC(2d948672) SHA1(cf15912d6dae5a450e0cfd796aa36ea5e521dc56))
|
||||
ROM_LOAD("g1_f850.bin", 0x2000, 0x1800, CRC(7d64a842) SHA1(d5884bb2af21c8027311478ee506beac6f46203d))
|
||||
ROM_LOAD("g2_f850.bin", 0x4000, 0x1800, CRC(e5ed8900) SHA1(03826882ce10fb5a6b3a9ccc85d3d1fe51979d0b))
|
||||
@ -1104,17 +886,15 @@ ROM_START(ti99_8)
|
||||
ROM_LOAD("g7_f850.bin", 0xE000, 0x1800, CRC(71534098) SHA1(75e87123efde885e27dd749e07cb189eb2cc45a8))
|
||||
|
||||
// Pascal library. 3 chips @ f860
|
||||
ROM_REGION(0x6000, region_gromlib3, 0)
|
||||
ROM_REGION(0x6000, GROMLIB3_REG, 0)
|
||||
ROM_LOAD("g0_f860.bin", 0x0000, 0x1800, CRC(0ceef210) SHA1(b89957fbff094b758746391a69dea6907c66b950))
|
||||
ROM_LOAD("g1_f860.bin", 0x2000, 0x1800, CRC(fc87de25) SHA1(4695b7f979f59a01ec16c55e4587c3379482b658))
|
||||
ROM_LOAD("g2_f860.bin", 0x4000, 0x1800, CRC(e833e350) SHA1(6ffe501981a1112be1af596a489d96e287fc6be5))
|
||||
|
||||
// Built-in RAM
|
||||
ROM_REGION(SRAM_SIZE, SRAM_TAG, 0)
|
||||
ROM_FILL(0x0000, SRAM_SIZE, 0x00)
|
||||
|
||||
ROM_REGION(DRAM_SIZE, DRAM_TAG, 0)
|
||||
ROM_FILL(0x0000, DRAM_SIZE, 0x00)
|
||||
// Speech ROM
|
||||
ROM_REGION(0x8000, SPEECHROM_REG, 0)
|
||||
ROM_LOAD("cd2325a.vsm", 0x0000, 0x4000, CRC(1f58b571) SHA1(0ef4f178716b575a1c0c970c56af8a8d97561ffe))
|
||||
ROM_LOAD("cd2326a.vsm", 0x4000, 0x4000, CRC(65d00401) SHA1(a367242c2c96cebf0e2bf21862f3f6734b2b3020))
|
||||
ROM_END
|
||||
|
||||
#define rom_ti99_8e rom_ti99_8
|
||||
|
Loading…
Reference in New Issue
Block a user