summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/bus.lua2
-rw-r--r--src/devices/bus/ti99_peb/pcode.cpp208
-rw-r--r--src/devices/bus/ti99_peb/pcode.h21
-rw-r--r--src/devices/bus/ti99_peb/peribox.cpp2
-rw-r--r--src/devices/bus/ti99x/998board.cpp2316
-rw-r--r--src/devices/bus/ti99x/998board.h614
-rw-r--r--src/devices/bus/ti99x/datamux.cpp397
-rw-r--r--src/devices/bus/ti99x/datamux.h98
-rw-r--r--src/devices/bus/ti99x/genboard.cpp14
-rw-r--r--src/devices/bus/ti99x/genboard.h3
-rw-r--r--src/devices/bus/ti99x/grom.cpp269
-rw-r--r--src/devices/bus/ti99x/grom.h108
-rw-r--r--src/devices/bus/ti99x/gromport.cpp464
-rw-r--r--src/devices/bus/ti99x/gromport.h83
-rw-r--r--src/devices/bus/ti99x/ti99defs.h48
-rw-r--r--src/devices/bus/ti99x/videowrp.cpp17
-rw-r--r--src/devices/bus/ti99x/videowrp.h30
-rw-r--r--src/mame/drivers/ti99_4p.cpp8
-rw-r--r--src/mame/drivers/ti99_4x.cpp155
-rw-r--r--src/mame/drivers/ti99_8.cpp498
20 files changed, 3162 insertions, 2193 deletions
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index 5423c224127..f52e4b03fe6 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -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",
diff --git a/src/devices/bus/ti99_peb/pcode.cpp b/src/devices/bus/ti99_peb/pcode.cpp
index 57ee6462874..ff0d9b4c9d5 100644
--- a/src/devices/bus/ti99_peb/pcode.cpp
+++ b/src/devices/bus/ti99_peb/pcode.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,28 +184,14 @@ 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 )
{
@@ -169,6 +199,22 @@ WRITE_LINE_MEMBER( ti_pcode_card_device::ready_line )
}
/*
+ 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
may be able to write to them, but not necessarily read them again.)
@@ -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_active = ioport(ACTIVE_TAG)->read();
- m_switch = 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 )
diff --git a/src/devices/bus/ti99_peb/pcode.h b/src/devices/bus/ti99_peb/pcode.h
index c2a81a1395c..71664682261 100644
--- a/src/devices/bus/ti99_peb/pcode.h
+++ b/src/devices/bus/ti99_peb/pcode.h
@@ -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
diff --git a/src/devices/bus/ti99_peb/peribox.cpp b/src/devices/bus/ti99_peb/peribox.cpp
index a89f86d13ef..52274505533 100644
--- a/src/devices/bus/ti99_peb/peribox.cpp
+++ b/src/devices/bus/ti99_peb/peribox.cpp
@@ -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++)
{
diff --git a/src/devices/bus/ti99x/998board.cpp b/src/devices/bus/ti99x/998board.cpp
index 0d1f081ed1b..595ee5f77b1 100644
--- a/src/devices/bus/ti99x/998board.cpp
+++ b/src/devices/bus/ti99x/998board.cpp
@@ -14,71 +14,795 @@
Note: The TI-99/8's internal codename was "Armadillo"
-==============================
- Mapper (codename "Amigo")
-==============================
- Initial setting of mapper (as defined in the power-up routine, TI-99/4A mode)
+ +-------+ +--------+
+ | CPU |========LogAddrBus======| Mapper |====PhysAddrBus==========
+ | TMS | || | AMIGO | ||
+ | 9995 | +----------+ | | +----------+
+ | | | Logical | +--------+ | Physical |
+ +-------+ | space | | | space |
+ | decoder | | | decoder |
+ | VAQUERRO | | | MOFETTA |
+ +----------+ | +----------+
+ | | |
+ +--------------------+ | +---------------------+
+ | Devices | | | Devices |
+ | +-------+ | | |
+ | ROM0 | SRAM | | | DRAM (POLLO) |
+ | Video | ---- | | | ROM1 |
+ | Speech | Maps--+--+ | Cartridge port |
+ | GROM +-------+ | PEB |
+ | Sound | | Hexbus (OSO) |
+ +--------------------+ +---------------------+
+
+ Custom chips
+ ------------
+ The chipset of the TI-99/8 consists of five specifically programmed chips.
+ All are nicknamed after some Spanish words (albeit sometimes misspelled)
+
+ VAQUERRO: Logical Address Space decoder ("Vaquero" = "Cowboy")
+ MOFETTA : Physical Address Space decoder ("Mofeta" = "Skunk")
+ AMIGO : Mapper ("Amigo" = "Friend")
+ OSO : Hexbus adapter ("Oso" = "Bear")
+ POLLO : DRAM controller (Not emulated) ("Pollo" = "Chicken")
+
+ See the comments for the respective chip implementation for details.
+
+
+ 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.
- 0 00ff0000 -> Unmapped; logical address 0000...0fff = ROM0
- 1 00ff0000 -> Unmapped; logical address 1000...1fff = ROM0
- 2 00000800 -> DRAM; 2000 = 000800, 2fff = 0017ff
- 3 00001800 -> DRAM; 3000 = 001800, 3fff = 0027ff
- 4 00ff4000 -> DSR space (internal / ioport)
- 5 00ff5000 -> DSR space (internal / ioport)
- 6 00ff6000 -> Cartridge space (6000..6fff)
- 7 00ff7000 -> Cartridge space (7000..7fff)
- 8 00ff0000 -> Unmapped; device ports (VDP) and SRAM
- 9 00ff0000 -> Unmapped; device ports (Speech, GROM)
- A 00002800 -> DRAM; a000 = 002800, afff = 0037ff
- B 00003800 -> DRAM; b000 = 003800, bfff = 0047ff
- C 00004800 -> DRAM; c000 = 004800, cfff = 0057ff
- D 00005800 -> DRAM; d000 = 005800, dfff = 0067ff
- E 00006800 -> DRAM; e000 = 006800, efff = 0077ff
- F 00007800 -> DRAM; f000 = 007800, ffff = 0087ff
- Format of map table entry (not emulated)
+ CRU map (I/O address space)
+ ===========================
+ 0000-003e: TMS9901 system interface (see ti99_8.c)
+ 1700-17fe: Hexbus
+ 2000-26fe: Future external devices
+ 2700-27fe: Additional ROM ("internal DSR")
+ 2702 : System reset (when set to 1)
+ 2800-3ffe: Future external devices
+ 4000-fffe: Future external devices
- +------+------+------+------+---+---+---+---------+----------+---------+
- | WProt| XProt| RProt| * | 0 | 0 | 0 | Upper | High | Low |
- +------+------+------+------+---+---+---+---------+----------+---------+
+ The TMS9995 offers the full 15-bit CRU address space. Devices designed for
+ the TI-99/4A should only be accessed in the area 1000-1ffe. They will (by
+ design) incompletely decode the CRU address and be mirrored in the higher
+ areas.
- WProt: Write protection if set to 1
- XProt: Execute protection if set to 1
- RProt: Read protection if set to 1
+ Note that the cartridge port of the TI-99/8 offers support for 16K ROM
+ cartridges, but lacks CRU support.
- When a protection violation occurs, the tms9901 INT1* pin is pulled low
- (active). The pin remains low until the mapper status register is read.
+ Michael Zapf, October 2010
+ February 2012: Rewritten as class
+ March 2016: Redesigned for custom chip emulation
- Address handling
- ----------------
- Physical address is (Upper * 2^16) + (High * 2^8) + Low
+ Informations taken from
+ [1] ARMADILLO PRODUCT SPECIFICATIONS
+ [2] TI-99/8 Graphics Programming Language interpreter
- The mapper calculates the actual physical address by looking up the
- table entry from the first four bits of the logical address and then
- *adding* the remaining 12 bits of the logical address on the map value.
+***************************************************************************/
- The value 0xff0000 is used to indicate a non-mapped area.
+// TODO:
+// - PEB
- Mapper control register
- -----------------------
- The mapper control register is used to initiate a map load/save operation.
+#include "998board.h"
- +---+---+---+---+---+---+---+---+
- | 0 | 0 | 0 | 0 | Map File | RW|
- +---+---+---+---+---+---+---+---+
+#define TRACE_CRU 0
+#define TRACE_ADDRESS 0
+#define TRACE_MAP 0
+#define TRACE_OSO 0
+#define TRACE_DECODE 0
+#define TRACE_READY 0
+#define TRACE_MEM 0
+#define TRACE_CLOCK 0
+#define TRACE_DETAIL 0
+#define TRACE_MOFETTA 0
+#define TRACE_AMIGO 0
+#define TRACE_WS 0
+#define TRACE_CPURY 0
+#define TRACE_GROM 0
+#define TRACE_PUNMAP 0
- The map file is a number from 0-7 indicating the set of map values for the
- operation, which means the location in SRAM where the next 64 values are
- loaded from or stored into.
+mainboard8_device::mainboard8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MAINBOARD8, "TI-99/8 Mainboard", tag, owner, clock, "ti998_mainboard", __FILE__),
+ m_pending_write(false),
+ m_speech_ready(true),
+ m_sound_ready(true),
+ m_pbox_ready(true),
+ m_ready(*this),
+ m_console_reset(*this),
+ m_hold_line(*this),
+ m_vaquerro(*this, VAQUERRO_TAG),
+ m_mofetta(*this, MOFETTA_TAG),
+ m_amigo(*this, AMIGO_TAG),
+ m_oso(*this, OSO_TAG)
+{
+}
- RW = 1: load from SRAM into mapper
- RW = 0: store from mapper into SRAM
+// =============== CRU bus access ==================
- When read, the mapper register returns the violation flags:
- +------+------+------+---+---+---+---+---+
- | WProt| XProt| RProt| 0 | 0 | 0 | 0 | 0 |
- +------+------+------+---+---+---+---+---+
+READ8Z_MEMBER(mainboard8_device::crureadz)
+{
+ m_peb->crureadz(space, offset, value);
+}
+
+/*
+ CRU handling. Mofetta is the only chip that bothers to handle it, beside the PEB
+*/
+WRITE8_MEMBER(mainboard8_device::cruwrite)
+{
+ m_mofetta->cruwrite(space, offset, data);
+ m_peb->cruwrite(space, offset, data);
+}
+
+// =============== Memory bus access ==================
+
+WRITE_LINE_MEMBER( mainboard8_device::dbin_in )
+{
+ m_dbin_level = (line_state)state;
+}
+
+SETOFFSET_MEMBER( mainboard8_device::setoffset )
+{
+ if (TRACE_ADDRESS) logerror("set %s %04x\n", (m_dbin_level==ASSERT_LINE)? "R" : "W", offset);
+
+ // No data is waiting on the data bus
+ m_pending_write = false;
+
+ // Memory cycle begins
+ m_vaquerro->memen_in(ASSERT_LINE);
+ m_amigo->memen_in(ASSERT_LINE);
+
+ // Save the logical address
+ m_logical_address = offset;
+ m_physical_address = 0;
+
+ // In TI's bit order, A14 is the second line from the right side (2^1)
+ m_A14_set = ((m_logical_address & 2)!=0); // Needed for clock_in
+
+ // Check for match in logical space
+ m_vaquerro->set_address(space, m_logical_address, m_dbin_level);
+
+ // Select GROMs if addressed
+ select_groms();
+
+ // Speech select lines will always be asserted/cleared as soon as the address is available
+ m_speech->wsq_w((m_vaquerro->spwt_out() == ASSERT_LINE)? FALSE : TRUE);
+ m_speech->rsq_w((m_vaquerro->sprd_out() == ASSERT_LINE)? FALSE : TRUE);
+
+ // If it is a logical space address, tell the mapper to stay inactive
+ line_state lasreq = (line_state)m_vaquerro->lascsq_out();
+ m_amigo->lascs_in(lasreq);
+ m_mofetta->lascs_in(lasreq);
+
+ // Need to set the address in any case so that the lines can be cleared
+ m_amigo->set_address(space, m_logical_address);
+
+ // AMIGO is the one to control the READY line to the CPU
+ // MOFETTA does not contribute to READY
+ m_ready(m_amigo->cpury_out());
+}
+
+WRITE_LINE_MEMBER( mainboard8_device::reset_console )
+{
+ m_console_reset(state);
+}
+
+WRITE_LINE_MEMBER( mainboard8_device::hold_cpu )
+{
+ m_hold_line(state);
+}
+
+/*
+ HOLD Acknowledge from the CPU
+*/
+WRITE_LINE_MEMBER( mainboard8_device::holda_line )
+{
+ m_amigo->holda_in(state);
+}
+
+/*
+ Clock line from the CPU. Forward to the custom chips.
+*/
+WRITE_LINE_MEMBER( mainboard8_device::clock_in )
+{
+ if (TRACE_CLOCK) logerror("CLKOUT = %d\n", state);
+
+ // Propagate to Vaquerro; may change GGRDY (trailing edge) and the GROM select lines
+ m_vaquerro->clock_in((line_state)state);
+
+ // Set the incoming ready line of Amigo (Mapper) before the clock
+ bool readycomb = ((m_vaquerro->ggrdy_out()==ASSERT_LINE) && m_speech_ready && m_sound_ready && m_pbox_ready);
+ m_amigo->srdy_in(readycomb? ASSERT_LINE : CLEAR_LINE);
+
+ // This may change the incoming READY lines of Vaquerro
+ if (state==CLEAR_LINE) select_groms();
+
+ m_amigo->clock_in((line_state)state);
+
+ // Mofetta only needs the clock to produce the GROM clock
+ m_mofetta->clock_in(state);
+
+ m_mofetta->skdrcs_in(m_amigo->skdrcs_out());
+
+ int gromclk = m_mofetta->gromclk_out();
+
+ if (gromclk != m_gromclk) // when it changed, propagate to the GROMs
+ {
+ m_gromclk = gromclk;
+ for (int i=0; i < 8; i++)
+ {
+ if (i < 3)
+ {
+ m_sgrom[i]->gclock_in(gromclk);
+ m_p3grom[i]->gclock_in(gromclk);
+ }
+ m_tsgrom[i]->gclock_in(gromclk);
+ m_p8grom[i]->gclock_in(gromclk);
+ }
+ m_gromport->gclock_in(gromclk);
+ }
+
+ // Check video for writing
+ if (m_pending_write && m_vaquerro->vdpwt_out()==ASSERT_LINE)
+ {
+ if (m_A14_set) m_video->register_write(*m_space, 0, m_latched_data);
+ else m_video->vram_write(*m_space, 0, m_latched_data);
+ m_pending_write = false;
+ if (TRACE_MEM) logerror("Write %04x (video) <- %02x\n", m_logical_address, m_latched_data);
+ cycle_end();
+ return;
+ }
+
+ // Propagate the READY signal
+ m_ready(m_amigo->cpury_out());
+
+ // In case we're reading, the CPU will now do the READ operation.
+ // Otherwise we must do the write operation now which we postponed before.
+
+ if (m_pending_write && (state==CLEAR_LINE))
+ {
+ if (m_amigo->skdrcs_out()==ASSERT_LINE)
+ {
+ m_dram[m_physical_address & 0xffff] = m_latched_data;
+ m_pending_write = false;
+ if (TRACE_MEM) logerror("Write %04x (phys %06x, DRAM) <- %02x\n", m_logical_address, m_physical_address, m_latched_data);
+ }
+
+ if (m_mofetta->alccs_out()==ASSERT_LINE)
+ {
+ m_oso->write(*m_space, m_physical_address>>1, m_latched_data);
+ m_pending_write = false;
+ if (TRACE_MEM) logerror("Write %04x (phys %06x, OSO) <- %02x\n", m_logical_address, m_physical_address, m_latched_data);
+ }
+
+ if (m_mofetta->cmas_out()==ASSERT_LINE)
+ {
+ m_gromport->romgq_line(ASSERT_LINE);
+ m_gromport->write(*m_space, m_physical_address & 0x3fff, m_latched_data);
+ m_pending_write = false;
+ if (TRACE_MEM) logerror("Write %04x (phys %06x, cartridge) <- %02x\n", m_logical_address, m_physical_address, m_latched_data);
+ }
+ else
+ {
+ m_gromport->romgq_line(CLEAR_LINE);
+ }
+
+ if (m_mofetta->dbc_out()==ASSERT_LINE)
+ {
+ m_peb->write(*m_space, m_physical_address, m_latched_data);
+ m_pending_write = false;
+ if (TRACE_MEM) logerror("Write %04x (phys %06x, PEB) <- %02x\n", m_logical_address, m_physical_address, m_latched_data);
+ }
+ }
+
+ if (m_dbin_level==CLEAR_LINE && !m_pending_write) // Memory cycle ends
+ cycle_end();
+}
+
+void mainboard8_device::select_groms()
+{
+ // Select the GROM libs
+ // Note that we must also deselect them again, so we have to visit each
+ // one of them
+
+ int select = m_vaquerro->gromcs_out();
+
+ // Avoid to be called too often; this would have a bad penalty on emulation performance
+ // This simple check actually increases bench performance from 120% to 240%
+ if (select != m_prev_grom)
+ {
+ m_prev_grom = select;
+ int lines = (m_dbin_level==ASSERT_LINE)? GROM_M_LINE : 0;
+ if (m_A14_set) lines |= GROM_MO_LINE;
+
+ for (int i=0; i < 8; i++)
+ {
+ if (i < 3)
+ {
+ m_sgrom[i]->set_lines(*m_space, lines, select & SGMSEL);
+ m_p3grom[i]->set_lines(*m_space, lines, select & P3GSEL);
+ }
+ m_tsgrom[i]->set_lines(*m_space, lines, select & TSGSEL);
+ m_p8grom[i]->set_lines(*m_space, lines, select & P8GSEL);
+ }
+ // Write to the cartridge port. The GROMs on cartridges are accesses as system GROMs
+ if (select & SGMSEL) m_gromport->romgq_line(CLEAR_LINE);
+ m_gromport->set_gromlines(*m_space, lines, select & SGMSEL);
+ }
+
+ // If we're planning to write to the GROMs, let's do it right now
+ if (select !=0 && m_pending_write)
+ {
+ m_pending_write = false;
+ switch (select)
+ {
+ case SGMSEL:
+ for (int i=0; i < 3; i++)
+ {
+ m_sgrom[i]->write(*m_space, 0, m_latched_data);
+ }
+ if (TRACE_MEM) logerror("Write GS <- %02x\n", m_latched_data);
+ m_gromport->write(*m_space, 0, m_latched_data);
+ break;
+
+ case TSGSEL:
+ for (int i=0; i < 8; i++)
+ {
+ m_tsgrom[i]->write(*m_space, 0, m_latched_data);
+ }
+ if (TRACE_MEM) logerror("Write GT <- %02x\n", m_latched_data);
+ break;
+
+ case P8GSEL:
+ for (int i=0; i < 8; i++)
+ {
+ m_p8grom[i]->write(*m_space, 0, m_latched_data);
+ }
+ if (TRACE_MEM) logerror("Write G8 <- %02x\n", m_latched_data);
+ break;
+
+ case P3GSEL:
+ for (int i=0; i < 3; i++)
+ {
+ m_p3grom[i]->write(*m_space, 0, m_latched_data);
+ }
+ if (TRACE_MEM) logerror("Write G3 <- %02x\n", m_latched_data);
+ break;
+
+ default:
+ logerror("Error: Multiple GROM libs selected: SGM=%d TSG=%d P8G=%d P3G=%d\n", (select & SGMSEL)!=0, (select & TSGSEL)!=0, (select & P8GSEL)!=0, (select & P3GSEL)!=0);
+ break;
+ }
+ }
+}
+
+void mainboard8_device::set_paddress(int address)
+{
+ // Keep this value as the current address
+ m_physical_address = (m_physical_address << 16) | address;
+ if (TRACE_DETAIL) logerror("Setting physical address %06x\n", m_physical_address);
+
+ m_mofetta->set_address(*m_space, address, m_dbin_level);
+ m_peb->setaddress_dbin(*m_space, address, m_dbin_level);
+}
+
+WRITE_LINE_MEMBER( mainboard8_device::msast_in )
+{
+ if (TRACE_DETAIL) logerror("msast = %d\n", state);
+
+ // Start physical space cycle on the trailing edge
+ if (state==CLEAR_LINE)
+ {
+ m_mofetta->pmemen_in(ASSERT_LINE);
+ m_peb->memen_in(ASSERT_LINE);
+ }
+ m_mofetta->msast_in(state);
+ m_peb->msast_in(state);
+}
+
+
+READ8_MEMBER( mainboard8_device::read )
+{
+ UINT8 value = 0;
+ const char* what;
+
+ // =================================================
+ // Logical space
+ // =================================================
+ if (m_amigo->mapper_accessed())
+ {
+ value = m_amigo->read(space, 0);
+ what = "mapper";
+ goto readdone;
+ }
+
+ if (m_amigo->sramcs_out()==ASSERT_LINE)
+ {
+ value = m_sram[m_logical_address & 0x07ff];
+ what = "SRAM";
+ goto readdone;
+ }
+
+ if (m_vaquerro->lascsq_out()==ASSERT_LINE)
+ {
+ // VDP access
+ if (m_vaquerro->vdprd_out()==ASSERT_LINE)
+ {
+ value = m_A14_set? m_video->register_read(space, 0) : m_video->vram_read(space, 0);
+ what = "video";
+ goto readdone;
+ }
+
+ // System ROM0
+ if (m_vaquerro->sromcs_out()==ASSERT_LINE)
+ {
+ value = m_rom0[m_logical_address & 0x1fff];
+ what = "ROM0";
+ goto readdone;
+ }
+
+ // Speech
+ if (m_vaquerro->sprd_out()==ASSERT_LINE)
+ {
+ value = m_speech->status_r(space, 0) & 0xff;
+ what = "speech";
+ goto readdone;
+ }
+
+ // GROMs
+ switch (m_vaquerro->gromcs_out())
+ {
+ case SGMSEL:
+ for (int i=0; i < 3; i++)
+ {
+ m_sgrom[i]->readz(space, 0, &value);
+ }
+ m_gromport->readz(space, 0, &value);
+ if (TRACE_GROM && !m_A14_set) logerror("GS>%04x\n", m_sgrom[0]->debug_get_address()-1);
+ what = "system GROM";
+ goto readdone;
+
+ case TSGSEL:
+ for (int i=0; i < 8; i++)
+ {
+ m_tsgrom[i]->readz(space, 0, &value);
+ }
+ if (TRACE_GROM && !m_A14_set) logerror("GT>%04x\n", m_tsgrom[0]->debug_get_address()-1);
+ what = "TTS GROM";
+ goto readdone;
+
+ case P8GSEL:
+ for (int i=0; i < 8; i++)
+ {
+ m_p8grom[i]->readz(space, 0, &value);
+ }
+ if (TRACE_GROM && !m_A14_set) logerror("G8>%04x\n", m_p8grom[0]->debug_get_address()-1);
+ what = "P8 GROM";
+ goto readdone;
+
+ case P3GSEL:
+ for (int i=0; i < 3; i++)
+ {
+ m_p3grom[i]->readz(space, 0, &value);
+ }
+ if (TRACE_GROM && !m_A14_set) logerror("G3>%04x\n", m_p3grom[0]->debug_get_address()-1);
+ what = "P3 GROM";
+ goto readdone;
+ default:
+ break;
+ }
+
+ // These messages appear in fact every time that a GPL command writes
+ // an immediate value to a write-only address (like 9400) because the
+ // GPL interpreter always tries to load the value from the provided memory address first
+
+ logerror("Read %04x (unmapped) ignored\n", m_logical_address);
+
+ // Memory cycle ends
+ cycle_end();
+ return 0;
+ }
+ else
+ {
+ // =================================================
+ // Physical space
+ // =================================================
+ if (m_amigo->skdrcs_out()==ASSERT_LINE)
+ {
+ value = m_dram[m_physical_address & 0xffff];
+ what = "DRAM";
+ goto readdonephys;
+ }
+
+ if (m_mofetta->rom1cs_out()==ASSERT_LINE)
+ {
+ int address = (m_physical_address & 0x1fff);
+ if (m_mofetta->rom1am_out()==ASSERT_LINE) address |= 0x4000;
+ if (m_mofetta->rom1al_out()==ASSERT_LINE) address |= 0x2000;
+ value = m_rom1[address];
+
+ if (TRACE_MEM) logerror("Read %04x (ROM1@%04x) -> %02x\n", m_logical_address, address, value);
+ cycle_end();
+ return value;
+ }
+
+ if (m_mofetta->alccs_out()==ASSERT_LINE)
+ {
+ value = m_oso->read(*m_space, m_physical_address>>1);
+ what = "OSO";
+ goto readdonephys;
+ }
+
+ if (m_mofetta->prcs_out()==ASSERT_LINE)
+ {
+ value = m_pascalrom[m_physical_address & 0x3fff];
+ what = "PASCAL";
+ goto readdonephys;
+ }
+
+ if (m_mofetta->cmas_out()==ASSERT_LINE)
+ {
+ m_gromport->romgq_line(ASSERT_LINE);
+ m_gromport->readz(*m_space, m_physical_address & 0x3fff, &value);
+ what = "Cartridge";
+ goto readdonephys;
+ }
+
+ if (m_mofetta->dbc_out()==ASSERT_LINE)
+ {
+ m_peb->readz(*m_space, m_physical_address & 0xffff, &value);
+ what = "PEB";
+ goto readdonephys;
+ }
+
+ if (TRACE_PUNMAP) logerror("Read %04x (phys %06x, unmapped) ignored\n", m_logical_address, m_physical_address);
+
+ // Memory cycle ends
+ cycle_end();
+ return 0;
+ }
+
+
+readdone:
+ if (TRACE_MEM) logerror("Read %04x (%s) -> %02x\n", m_logical_address, what, value);
+ cycle_end();
+ return value;
+
+readdonephys:
+ if (TRACE_MEM) logerror("Read %04x (phys %06x, %s) -> %02x\n", m_logical_address, m_physical_address, what, value);
+ cycle_end();
+ return value;
+}
+
+void mainboard8_device::cycle_end()
+{
+ // Memory cycle ends
+ m_vaquerro->memen_in(CLEAR_LINE);
+ m_amigo->memen_in(CLEAR_LINE);
+ m_mofetta->pmemen_in(CLEAR_LINE);
+ m_peb->memen_in(CLEAR_LINE);
+}
+
+/*
+ When writing, the emulation relies on a push mechanism; the write
+ operation follows the setaddress operation immediately.
+
+ If the READY line is pulled down due to the mapping process, we must
+ store the data bus value until the physical address is available.
+*/
+WRITE8_MEMBER( mainboard8_device::write )
+{
+ m_latched_data = data;
+ m_space = &space;
+ m_pending_write = true;
+
+ // Some logical space devices can be written immediately
+ // GROMs and video must wait to be selected
+ if (m_amigo->mapper_accessed())
+ {
+ if (TRACE_MEM) logerror("Write %04x (mapper) <- %02x\n", m_logical_address, data);
+ m_amigo->write(space, 0, data);
+ m_pending_write = false;
+ }
+
+ // Sound ... we have to put it before SRAM because in compatibility mode the
+ // sound address lies within the SRAM area
+ if (m_vaquerro->sccs_out()==ASSERT_LINE)
+ {
+ if (TRACE_MEM) logerror("Write %04x (sound) <- %02x\n", m_logical_address, data);
+ m_sound->write(space, 0, data); // Sound chip will lower READY after this access
+ m_pending_write = false;
+ }
+ else
+ {
+ // SRAM
+ if (m_amigo->sramcs_out()==ASSERT_LINE)
+ {
+ if (TRACE_MEM) logerror("Write %04x (SRAM) <- %02x\n", m_logical_address, data);
+ m_sram[m_logical_address & 0x07ff] = data;
+ m_pending_write = false;
+ }
+ }
+
+ // Speech
+ if (m_vaquerro->spwt_out()==ASSERT_LINE)
+ {
+ if (TRACE_MEM) logerror("Write %04x (speech) <- %02x\n", m_logical_address, data);
+ m_speech->data_w(space, 0, data);
+ m_pending_write = false;
+ }
+
+ if (!m_pending_write)
+ cycle_end();
+
+ // The remaining physical devices will respond as soon as the physical address is completely set
+}
+
+/*
+ Set 99/4A compatibility mode (CRUS=1)
+*/
+WRITE_LINE_MEMBER( mainboard8_device::crus_in )
+{
+ if (TRACE_CRU) logerror("%s CRUS\n", (state==1)? "Assert" : "Clear");
+ m_vaquerro->crus_in(state);
+ m_amigo->crus_in(state);
+}
+
+/*
+ Set mapper /PTGEN line ("Pascal and Text-to-speech GROMs enable").
+ Note that PTGEN is negative logic.
+*/
+WRITE_LINE_MEMBER( mainboard8_device::ptgen_in )
+{
+ if (TRACE_CRU) logerror("%s PTGEN*\n", (state==0)? "Assert" : "Clear");
+ m_vaquerro->crusgl_in((state==0)? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+/*
+ READY lines, to be combined
+*/
+WRITE_LINE_MEMBER( mainboard8_device::system_grom_ready )
+{
+ m_vaquerro->sgmry(state);
+}
+
+WRITE_LINE_MEMBER( mainboard8_device::ptts_grom_ready )
+{
+ m_vaquerro->tsgry(state);
+}
+
+WRITE_LINE_MEMBER( mainboard8_device::p8_grom_ready )
+{
+ m_vaquerro->p8gry(state);
+}
+
+WRITE_LINE_MEMBER( mainboard8_device::p3_grom_ready )
+{
+ m_vaquerro->p3gry(state);
+}
+
+WRITE_LINE_MEMBER( mainboard8_device::sound_ready )
+{
+ m_sound_ready = state;
+}
+
+WRITE_LINE_MEMBER( mainboard8_device::speech_ready )
+{
+ // The TMS5200 implementation uses TRUE/FALSE, not ASSERT/CLEAR semantics
+ m_speech_ready = (state==FALSE)? ASSERT_LINE : CLEAR_LINE;
+}
+
+WRITE_LINE_MEMBER( mainboard8_device::pbox_ready )
+{
+ m_pbox_ready = state;
+}
+
+WRITE_LINE_MEMBER( mainboard8_device::ggrdy_in )
+{
+ m_amigo->srdy_in((state==ASSERT_LINE && m_speech_ready && m_sound_ready && m_pbox_ready)? ASSERT_LINE : CLEAR_LINE);
+}
+
+static const char *const glib0[] = { SYSGROM0_TAG, SYSGROM1_TAG, SYSGROM2_TAG };
+static const char *const glib1[] = { GLIB10_TAG, GLIB11_TAG, GLIB12_TAG, GLIB13_TAG, GLIB14_TAG, GLIB15_TAG, GLIB16_TAG, GLIB17_TAG };
+static const char *const glib2[] = { GLIB20_TAG, GLIB21_TAG, GLIB22_TAG, GLIB23_TAG, GLIB24_TAG, GLIB25_TAG, GLIB26_TAG, GLIB27_TAG };
+static const char *const glib3[] = { GLIB30_TAG, GLIB31_TAG, GLIB32_TAG };
+
+void mainboard8_device::device_start()
+{
+ logerror("Starting main board\n");
+ // Lines going to the main driver class, then to the CPU
+ m_ready.resolve_safe(); // READY
+ m_console_reset.resolve_safe(); // RESET
+ m_hold_line.resolve_safe(); // HOLD
+
+ // Setting up the links to the GROMs
+ for (int i=0; i < 8; i++)
+ {
+ if (i < 3)
+ {
+ m_sgrom[i] = downcast<tmc0430_device*>(machine().device(glib0[i]));
+ m_p3grom[i] = downcast<tmc0430_device*>(machine().device(glib3[i]));
+ }
+ m_tsgrom[i] = downcast<tmc0430_device*>(machine().device(glib1[i]));
+ m_p8grom[i] = downcast<tmc0430_device*>(machine().device(glib2[i]));
+ }
+
+ // Link to speech synthesizer
+ m_speech = downcast<cd2501ecd_device*>(machine().device(SPEECHSYN_TAG));
+
+ // Link to sound chip
+ m_sound = downcast<sn76496_base_device*>(machine().device(TISOUNDCHIP_TAG));
+
+ // Link to video
+ m_video = downcast<tms9118_device*>(machine().device(VDP_TAG));
+
+ // Link to cartridge port
+ m_gromport = downcast<gromport_device*>(machine().device(GROMPORT_TAG));
+
+ // Link to PEB
+ m_peb = downcast<peribox_device*>(machine().device(PERIBOX_TAG));
+
+ // Configure RAM and AMIGO
+ m_sram = std::make_unique<UINT8[]>(SRAM_SIZE);
+ m_dram = std::make_unique<UINT8[]>(DRAM_SIZE);
+
+ m_amigo->connect_sram(m_sram.get());
+
+ m_rom0 = machine().root_device().memregion(ROM0_REG)->base();
+ m_rom1 = machine().root_device().memregion(ROM1_REG)->base();
+ m_pascalrom = machine().root_device().memregion(PASCAL_REG)->base();
+}
+
+void mainboard8_device::device_reset()
+{
+ logerror("Resetting main board\n");
+ m_last_ready = CLEAR_LINE;
+ m_speech_ready = true;
+ m_sound_ready = true;
+ m_pbox_ready = true;
+ m_pending_write = false;
+ m_prev_grom = 0;
+}
+
+MACHINE_CONFIG_FRAGMENT( ti998_mainboard )
+ MCFG_DEVICE_ADD(VAQUERRO_TAG, VAQUERRO, 0)
+ MCFG_DEVICE_ADD(MOFETTA_TAG, MOFETTA, 0)
+ MCFG_DEVICE_ADD(AMIGO_TAG, AMIGO, 0)
+ MCFG_DEVICE_ADD(OSO_TAG, OSO, 0)
+MACHINE_CONFIG_END
+
+machine_config_constructor mainboard8_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( ti998_mainboard );
+}
+const device_type MAINBOARD8 = &device_creator<mainboard8_device>;
+
+
+/***************************************************************************
+ ===== VAQUERRO: Logical Address Space decoder =====
Logical address space (LAS)
===========================
@@ -150,649 +874,976 @@
f850-f85f: P-Code library #1 GROM read/write
f860-f86f: P-Code library #2 GROM read/write
- Physical address space (PAS)
- ============================
- The PAS is 24 bits wide and accessed via the custom mapper chip nicknamed
- "Amigo". The mapper exchanges map definitions with SRAM (see LAS). That
- means, a map can be prepared in SRAM, and for activating it, the mapper
- is accessed on its port, telling it to load or save a map.
-
- 000000-00ffff: 64 KiB console DRAM
- 010000-efffff: undefined
- f00000-f03fff: P-Code ROM (not mentioned in [1])
- f04000-feffff: undefined
- ff0000 : unmapped (code for mapper)
- ff0001-ff3fff: undefined
- ff4000-ff5fff: DSR ROM in Peripheral Box, Hexbus DSR (CRU 1700) or additional ROM (CRU 2700)
- ff6000-ff9fff: Cartridge ROM space
- ffa000-ffdfff: 16 KiB ROM1
- ffe000-ffe00f: Interrupt level sense
- ffe010-ffffff: undefined
+***************************************************************************/
- CRU map (I/O address space)
- ===========================
- 0000-003e: TMS9901 system interface (see ti99_8.c)
- 1700-17fe: Hexbus
- 2000-26fe: Future external devices
- 2700-27fe: Additional ROM ("internal DSR")
- 2702: System reset (when set to 1)
- 2800-3ffe: Future external devices
- 4000-fffe: Future external devices
+vaquerro_device::vaquerro_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+: device_t(mconfig, VAQUERRO, "Logical Address Space Decoder", tag, owner, clock, "ti998_vaquerro", __FILE__),
+ m_crus(ASSERT_LINE),
+ m_crugl(ASSERT_LINE),
+ m_ggrdy(ASSERT_LINE)
+{
+}
- The TMS9995 offers the full 15-bit CRU address space. Devices designed for
- the TI-99/4A should only be accessed in the area 1000-1ffe. They will (by
- design) incompletely decode the CRU address and be mirrored in the higher areas.
+SETADDRESS_DBIN_MEMBER( vaquerro_device::set_address )
+{
+ // Do the decoding
+ // state = dbin, offset = address
- Michael Zapf, October 2010
- February 2012: Rewritten as class
+ bool reading = (state==ASSERT_LINE);
+ bool sgfap = false;
+ bool tsgfap = false;
+ bool p8gfap = false;
+ bool p3gfap = false;
+ bool vfap = false;
- Informations taken from
- [1] ARMADILLO PRODUCT SPECIFICATIONS
- [2] TI-99/8 Graphics Programming Language interpreter
+ m_a14 = ((offset & 2)!=0)? ASSERT_LINE : CLEAR_LINE; // Needed for clock_in
-***************************************************************************/
+ m_dbin_level = (line_state)state;
-#include "998board.h"
+ int offbase = (offset & 0xfff1);
-#define TRACE_CRU 0
-#define TRACE_MEM 0
-#define TRACE_MAP 0
-#define TRACE_CONFIG 0
-#define TRACE_OSO 0
-#define TRACE_SPEECH 0
-#define TRACE_DETAIL 0
+ // =================== TI (compatibility) mode ======================
+ if (m_crus == ASSERT_LINE)
+ {
+ if (TRACE_DETAIL) logerror("Compatibility mode\n");
-mainboard8_device::mainboard8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : bus8z_device(mconfig, MAINBOARD8, "TI-99/8 Main board", tag, owner, clock, "ti998_mainboard", __FILE__),
- m_ready(*this), m_dsr_selected(false), m_hexbus_selected(false), m_CRUS(false), m_PTGE(false), m_waitcount(0), m_sram(nullptr), m_dram(nullptr), m_rom0(nullptr), m_rom1(nullptr), m_pcode(nullptr),
- m_oso(*this, OSO_TAG)
- { }
+ // SPRD (Speech read)
+ m_sprd = ((offbase==0x9000) && reading);
-/***************************************************************************
- CRU access
-***************************************************************************/
+ // SPWT (Speech write)
+ m_spwt = ((offbase==0x9400) && !reading);
-#define HEXBUS_CRU_BASE 0x1700
-#define MAPPER_CRU_BASE 0x2700
+ // Sound
+ m_sccs = ((offbase==0x8400)&& !reading);
-READ8Z_MEMBER(mainboard8_device::crureadz)
+ // ROM0
+ m_sromcs = (((offset & 0xe000)==0x0000) && reading);
+
+ // Video select
+ vfap = ((offbase==0x8800) && reading) || ((offbase==0x8c00) && !reading);
+
+ // System GROM
+ sgfap = ((offbase==0x9800) && reading) || ((offbase==0x9c00) && !reading);
+ }
+ // ====================== Native mode ======================
+ else
+ {
+ if (TRACE_DETAIL) logerror("Native mode\n");
+
+ // SPRD (Speech read)
+ m_sprd = ((offbase==0xf820) && reading);
+
+ // SPWT (Speech write)
+ m_spwt = ((offbase==0xf820) && !reading);
+
+ // Sound
+ m_sccs = ((offbase==0xf800) && !reading);
+
+ // Video
+ vfap = (offbase==0xf810);
+
+ // System GROM (read and write)
+ sgfap = (offbase==0xf830);
+ }
+
+ // These lines are not decoded for compatibility or native mode, only
+ // the line CRUGL determines whether they become visible.
+ tsgfap = (offbase==0xf840) && m_crugl;
+ p8gfap = (offbase==0xf850) && m_crugl;
+ p3gfap = (offbase==0xf860) && m_crugl;
+
+ // The LASREQ line says whether Vaquerro does the job, or whether it is Mofetta's turn.
+ m_grom_or_video = sgfap || tsgfap || p8gfap || p3gfap || vfap ;
+
+ m_lasreq = (m_sprd || m_spwt || m_sccs || m_sromcs || m_grom_or_video);
+
+ if (TRACE_DETAIL) logerror("sgfap=%d tsgfap=%d p8gfap=%d p3gfap=%d vfap=%d\n", sgfap, tsgfap, p8gfap, p3gfap, vfap);
+
+ // Pass the selection to the wait state generators
+ // and pick up the current select line states
+ m_sgmws.select_in(sgfap);
+ m_tsgws.select_in(tsgfap);
+ m_p8gws.select_in(p8gfap);
+ m_p3gws.select_in(p3gfap);
+ m_vidws.select_in(vfap);
+
+ m_gromsel = m_sgmws.select_out() | m_tsgws.select_out() | m_p8gws.select_out() | m_p3gws.select_out();
+
+ m_vdprd = (reading && (m_vidws.select_out()!=0));
+ m_vdpwt = (!reading && (m_vidws.select_out()!=0));
+
+ if (m_grom_or_video)
+ {
+ // We don't see the current selection now; only with next clock pulse.
+ m_mainboard->ggrdy_in(m_sry);
+ if (TRACE_READY) logerror("GGRDY = %d\n", m_sry);
+ }
+}
+
+WRITE_LINE_MEMBER( vaquerro_device::crusgl_in )
+{
+ m_crugl = (state==ASSERT_LINE);
+}
+
+WRITE_LINE_MEMBER( vaquerro_device::crus_in )
+{
+ m_crus = (line_state)state;
+}
+
+WRITE_LINE_MEMBER( vaquerro_device::memen_in )
{
- if (TRACE_CRU) logerror("%s: read CRU %04x ignored\n", tag(), offset);
- // Nothing here.
+ m_memen = (state==ASSERT_LINE);
}
/*
- CRU handling. We handle the internal device at CRU address 0x2700 via
- this mapper component.
+ Called by Mofetta
*/
-WRITE8_MEMBER(mainboard8_device::cruwrite)
+READ_LINE_MEMBER( vaquerro_device::lascsq_out )
{
- if ((offset & 0xff00)==MAPPER_CRU_BASE)
- {
- int bit = (offset & 0xff)>>1;
- switch (bit)
- {
- case 0:
- // Turn on/off the internal DSR
- m_dsr_selected = (data!=0);
- if (TRACE_CRU) logerror("%s: DSR select = %d\n", tag(), data);
- break;
- case 1:
- if (TRACE_CRU) logerror("%s: System reset by CRU request\n", tag());
- machine().schedule_soft_reset();
- break;
- }
- return;
- }
+ return (m_lasreq && m_memen)? ASSERT_LINE : CLEAR_LINE;
+}
- if ((offset & 0xff00)==HEXBUS_CRU_BASE)
- {
- int bit = (offset & 0xff)>>1;
- switch (bit)
- {
- case 0:
- // Turn on/off the Hexbus DSR
- m_hexbus_selected = (data!=0);
- if (TRACE_CRU) logerror("%s: Hexbus select = %d\n", tag(), data);
- break;
- default:
- if (TRACE_CRU) logerror("%s: Set CRU>%04x (Hexbus) to %d\n", tag(), offset,data);
- break;
- }
- return;
- }
+/*
+ Incoming ready lines from the GROM library
+*/
+WRITE_LINE_MEMBER( vaquerro_device::sgmry )
+{
+ if (TRACE_READY) logerror("Incoming SGMRY = %d\n", state);
+ m_sgmws.ready_in((line_state)state);
+}
- if ((offset & 0xff00)>=0x0100)
- {
- if (TRACE_CRU) logerror("%s: Set CRU>%04x (unknown) to %d\n", tag(), offset,data);
- return;
- }
+WRITE_LINE_MEMBER( vaquerro_device::tsgry )
+{
+ if (TRACE_READY) logerror("Incoming TSGRY = %d\n", state);
+ m_tsgws.ready_in((line_state)state);
}
-void mainboard8_device::CRUS_set(bool state)
+WRITE_LINE_MEMBER( vaquerro_device::p8gry )
{
- if (TRACE_CRU) logerror("%s: set CRUS=%d\n", tag(), state);
- m_CRUS = state;
+ if (TRACE_READY) logerror("Incoming 8GRY = %d\n", state);
+ m_p8gws.ready_in((line_state)state);
+}
+
+WRITE_LINE_MEMBER( vaquerro_device::p3gry )
+{
+ if (TRACE_READY) logerror("Incoming P3GRY = %d\n", state);
+ m_p3gws.ready_in((line_state)state);
}
/*
- Note that PTGEN is negative logic. We invert these semantics here.
+ Outgoing READY
*/
-void mainboard8_device::PTGE_set(bool state)
+READ_LINE_MEMBER( vaquerro_device::ggrdy_out )
{
- if (TRACE_CRU) logerror("%s: set PTGEN=%d\n", tag(), state? 1:0);
- m_PTGE = state;
+ if (TRACE_READY) logerror("GGRDY out = %d\n", m_ggrdy);
+ return m_ggrdy;
}
-/***************************************************************************
- Access by address map
-***************************************************************************/
+/*
+ Select lines
+*/
+
+// =========================
+
+int vaquerro_device::gromcs_out()
+{
+ return m_gromsel;
+}
+
+// =========================
+
+READ_LINE_MEMBER( vaquerro_device::vdprd_out )
+{
+ return (m_vdprd && m_memen)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER( vaquerro_device::vdpwt_out )
+{
+ return (m_vdpwt && m_memen)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER( vaquerro_device::sprd_out )
+{
+ return (m_sprd && m_memen)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER( vaquerro_device::spwt_out )
+{
+ return (m_spwt && m_memen)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER( vaquerro_device::sromcs_out )
+{
+ return (m_sromcs && m_memen)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER( vaquerro_device::sccs_out )
+{
+ return (m_sccs && m_memen)? ASSERT_LINE : CLEAR_LINE;
+}
/*
- This method is called via the address map.
+ Incoming clock signal.
+
+ The Vaquerro has a Wait State generation logic circuit for the video
+ processor and all 4 GROM libraries. Each one has its separate generator.
+ The GROMs get a 16 cycle wait period after their access, while the video
+ processors gets an 8 cycle wait period. If during that period another
+ access occurs, the system READY line will be cleared, triggering wait
+ states in the CPU.
*/
-READ8_MEMBER( mainboard8_device::readm )
+WRITE_LINE_MEMBER( vaquerro_device::clock_in )
{
- UINT8 value = 0;
- bool found;
- if (TRACE_DETAIL) logerror("%s: read from %04x\n", tag(), offset);
- found = access_logical_r(space, offset, &value, mem_mask);
- m_waitcount = 2;
+ line_state level = (line_state)state;
- if (!found)
- {
- // In that case, the address decoder could not find a suitable device.
- // This means the logical address is transformed by the mapper.
- // NOTE: Use "+", not OR. The offset is not a prefix.
- UINT32 pas_address = m_pas_offset[(offset & 0xf000)>>12] + (offset & 0xfff);
+ // Propagate to the wait state generators (note that we need both clock levels)
+ m_sgmws.clock_in(level);
+ m_tsgws.clock_in(level);
+ m_p8gws.clock_in(level);
+ m_p3gws.clock_in(level);
+ m_vidws.clock_in(level);
+
+ // Collect the selections
+ // Each one has its own indication, defined at init time
+ m_gromsel = m_sgmws.select_out() | m_tsgws.select_out() | m_p8gws.select_out() | m_p3gws.select_out();
+
+ bool reading = (m_dbin_level==ASSERT_LINE);
- // So now let's do the same as above with physical addresses
- access_physical_r(space, pas_address, &value, mem_mask);
+ m_vdprd = (reading && (m_vidws.select_out()!=0));
+ m_vdpwt = (!reading && (m_vidws.select_out()!=0));
- // The PAS area requires one more wait state, as the address bus
- // is multiplexed
- m_waitcount = 3;
+ // Get the READY levels from the GROMs
+ if (level==CLEAR_LINE)
+ {
+ m_sry = m_sgmws.ready_out() || m_tsgws.ready_out() || m_p8gws.ready_out() || m_p3gws.ready_out() || m_vidws.ready_out();
+ if (TRACE_WS) logerror("ready_out = (%d, %d, %d, %d, %d)\n", m_sgmws.ready_out(), m_tsgws.ready_out(), m_p8gws.ready_out(), m_p3gws.ready_out(),m_vidws.ready_out());
}
- // Insert wait states and let CPU enter wait state
- m_ready(CLEAR_LINE);
+ // If the output gate is closed, propagate ASSERT_LINE (pulled up)
+ m_ggrdy = (!m_grom_or_video || m_sry)? ASSERT_LINE : CLEAR_LINE;
+}
- return value;
+
+void vaquerro_device::device_start()
+{
+ logerror("Starting\n");
+ m_mainboard = downcast<mainboard8_device*>(owner());
+ m_sgmws.init(SGMSEL);
+ m_tsgws.init(TSGSEL);
+ m_p8gws.init(P8GSEL);
+ m_p3gws.init(P3GSEL);
+ m_vidws.init(VIDSEL);
}
-WRITE8_MEMBER( mainboard8_device::writem )
+void vaquerro_device::device_reset()
{
- bool found;
+ m_ggrdy = ASSERT_LINE;
+ m_vdpwt = m_vdprd = CLEAR_LINE;
+ m_gromsel = 0;
+ m_sgmws.treset_in(ASSERT_LINE);
+ m_tsgws.treset_in(ASSERT_LINE);
+ m_p8gws.treset_in(ASSERT_LINE);
+ m_p3gws.treset_in(ASSERT_LINE);
+ m_vidws.treset_in(ASSERT_LINE);
+}
- // Look for components responding to the logical address
- found = access_logical_w(space, offset, data, mem_mask);
- m_waitcount = 2;
+/*
+ Wait state generation logic inside Vaquerro
+
+ Analysis of the logic diagram of the Vaquerro delivers the following
+ behavior (for the first GROM library; similar behavior applies for the
+ other libraries). Note that the CLKOUT line is inverted.
+
+ 1. When the GROMs are unselected by address (SGFAP), the SRY line is Z
+ (System READY). The GROM ready line (SGMRY) has no effect.
+ 2. When SGFAP is asserted while the internal counter is off, the
+ READY line changes from Z to Low and the GROM select line (SGCS) is
+ asserted (both immediately, before the next tick edge). SGMRY has no effect.
+ The circuit state is constant during further clock ticks.
+ 3. After being selected, when SGMRY is asserted (GROM is ready), SRY
+ changes to High on the next trailing edge. This will allow the
+ CPU to complete the GROM access on the next cycle,
+ and the address bus will change, typically deselecting the GROMs.
+ Until this deselection, the circuit state remains constant
+ (SGCS asserted, READY=H).
+ 4. When the GROMs are deselected, SRY changes to Z, and SGCS is cleared
+ (immediately). A counter is started at 0 that is incremented on each clock
+ tick (leading edge).
+ 5. When SGFAP is asserted while the counter is less that 15, SRY changes
+ to Low immediately. SGCS remains cleared, so the GROMs are not selected.
+ While SGFAP stays cleared, the counter completes its way to 15,
+ then 0, and turns off.
+ 6. When the counter reaches 15, it returns to 0 on the next tick
+ (leading). On the following trailing edge, the GROM select line is
+ asserted, while the READY line remains Low.
+ 7. Continue at 3.
+*/
+void waitstate_generator::select_in(bool addressed)
+{
+ m_addressed = addressed;
+}
- if (!found)
- {
- // In that case, the address decoder could not find a suitable device.
- // This means the logical address is transformed by the mapper.
- // NOTE: Use "+", not OR. The offset is not a prefix.
- UINT32 pas_address = m_pas_offset[(offset & 0xf000)>>12] + (offset & 0xfff);
+int waitstate_generator::select_out()
+{
+ return (!m_counting && m_addressed)? m_selvalue : 0;
+}
- // So now let's do the same as above with physical addresses
- access_physical_w(space, pas_address, data, mem_mask);
+/*
+ Should be low by default.
+*/
+line_state waitstate_generator::ready_out()
+{
+ return (m_ready && !m_counting && m_generate)? ASSERT_LINE : CLEAR_LINE;
+}
- // The PAS area requires one more wait state, as the address bus
- // is multiplexed
- m_waitcount = 3;
- }
+bool waitstate_generator::is_counting()
+{
+ return m_counting;
+}
- // Insert wait states and let CPU enter wait state
- m_ready(CLEAR_LINE);
+bool waitstate_generator::is_generating()
+{
+ return m_generate;
+}
+
+bool waitstate_generator::is_ready()
+{
+ return m_ready;
}
-/***************************************************************************
- Indirect calls (mapper calls itself)
-***************************************************************************/
/*
- This method is called by the mapper itself for
- f870 (NATIVE): mapper: ignore
- 8810 (TI99EM): mapper: ignore
- ff4000 (PHYSIC): DSR
+ READY in. This may only show an effect with the next trailing edge of CLKOUT.
*/
-READ8Z_MEMBER( mainboard8_device::readz )
+void grom_waitstate_generator::ready_in(line_state ready)
{
- if ((offset & 0xffe000)==0xff4000)
+ m_ready = (ready==ASSERT_LINE);
+}
+
+void grom_waitstate_generator::clock_in(line_state clkout)
+{
+ if (clkout == ASSERT_LINE)
+ {
+ if (m_counting) m_counter++;
+ }
+ else
{
- if (m_dsr_selected)
+ if (m_counting && m_counter==16)
{
- // Starts at 0x4000 in the image
- *value = m_rom1[0x4000 | (offset & 0x1fff)];
- if (TRACE_MEM) logerror("%s: (intDSR) %04x -> %02x\n", tag(), offset, *value);
+ m_counter = 0;
+ m_counting = false;
}
else
{
- if (m_hexbus_selected)
- {
- if ((offset & 0x1ff0)==0x1ff0)
- {
- *value = m_oso->read(space, (offset>>1) & 0x0003);
- }
- else
- {
- // Starts at 0x6000 in the image
- *value = m_rom1[0x6000 | (offset & 0x1fff)];
- if (TRACE_MEM) logerror("%s: (HexDSR) %04x -> %02x\n", tag(), offset, *value);
- }
- }
+ if (!m_addressed && m_generate) m_counting = true;
+ m_generate = ((m_addressed || m_counting) && (m_counter != 15));
}
}
+}
+
+void waitstate_generator::treset_in(line_state reset)
+{
+ if (reset==ASSERT_LINE)
+ {
+ m_counter = 0;
+ m_generate = m_counting = m_addressed = false;
+ }
+}
+
+void video_waitstate_generator::clock_in(line_state clkout)
+{
+ if (clkout == ASSERT_LINE)
+ {
+ if (m_counting) m_counter++;
+ }
else
{
- if (((offset & 0xfff0)==0xf870 && m_CRUS==false)||(((offset & 0xfff0)==0x8810 && m_CRUS==true)))
+ if (m_counting && m_counter==7)
+ {
+ m_counter = 0;
+ m_counting = false;
+ }
+ else
{
- if (TRACE_MEM) logerror("%s: read access to mapper ignored: %04x\n", tag(), offset);
+ if (!m_addressed && m_generate) m_counting = true;
+ m_generate = ((m_addressed || m_counting) && (m_counter != 6));
}
}
}
+const device_type VAQUERRO = &device_creator<vaquerro_device>;
+
+/***************************************************************************
+ ===== MOFETTA: Physical Address Space decoder =====
+
+ Physical address space (PAS)
+ ============================
+ The PAS is 24 bits wide and accessed via the custom mapper chip nicknamed
+ "Amigo". The mapper exchanges map definitions with SRAM (see LAS). That
+ means, a map can be prepared in SRAM, and for activating it, the mapper
+ is accessed on its port, telling it to load or save a map.
+
+ 000000-00ffff: 64 KiB console DRAM
+ 010000-efffff: undefined
+
+ f00000-f03fff: PASCAL support ROM (not mentioned in [1])
+
+ f04000-feffff: undefined
+ ff0000 : unmapped (code for mapper)
+ ff0001-ff3fff: undefined
+ ff4000-ff5fff: DSR ROM in Peripheral Box, Hexbus DSR (CRU 1700) or additional ROM (CRU 2700)
+ ff6000-ff9fff: Cartridge ROM space
+ ffa000-ffdfff: 16 KiB ROM1
+ ffe000-ffe00f: Interrupt level sense
+ ffe010-ffffff: undefined
+
+
+***************************************************************************/
+
+enum
+{
+ UNDEF=0,
+ DRAM,
+ PASCAL,
+ INTERNAL
+};
+
+mofetta_device::mofetta_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, MOFETTA, "Physical Address Space Decoder", tag, owner, clock, "ti998_mofetta", __FILE__),
+ m_gotfirstword(false)
+{
+}
+
+SETADDRESS_DBIN_MEMBER( mofetta_device::set_address )
+{
+ if (!m_gotfirstword)
+ {
+ // Store the first word and wait for clearing of MSAST
+ if (TRACE_MOFETTA) logerror("Got the upper word of the address: %04x\n", offset);
+ m_address_latch = offset;
+ }
+ else
+ {
+ // Second part - now decode the address
+ if (TRACE_MOFETTA) logerror("Got the lower word of the address: %04x\n", offset);
+
+ bool acs, tcs, rcs, acsx;
+ bool reading = (state==ASSERT_LINE);
+ int offbase = (offset & 0xe000);
+
+ // PASCAL ROM select (16K)
+ m_prcs = (m_prefix == 0xf0) && ((offset & 0xc000) == 0x0000);
+
+ // Hexbus select
+ acs = (m_prefix == 0xff) && (offbase == 0x4000) && m_alcpg;
+
+ // Internal DSR select (ff4000-ff5fff @ CRU>2700)
+ tcs = (m_prefix == 0xff) && (offbase == 0x4000) && m_txspg;
+
+ // Hexbus select (ff4000-ff5fef @ CRU>1700), excluding OSO
+ acsx = acs && ((offset & 0x1ff0)!=0x1ff0);
+
+ // Upper 16K of ROM1
+ m_rom1am = !((offbase == 0xa000) || (offbase == 0xc000));
+
+ // ROM select
+ rcs = (m_prefix == 0xff) && reading && !m_rom1am;
+
+ // ROM1 select (containing 16K ROM, 8K TTS, 8K ACS)
+ m_rom1cs = tcs || rcs || acsx;
+
+ // Accessing OSO (ff5ff0 @ CRU>1700)
+ m_alccs = acs && ((offset & 0x1ff0)==0x1ff0);
+
+ // Second half of ROM or ACS
+ m_rom1al = reading && (m_prefix == 0xff) && ((offbase == 0xc000) || acs);
+
+ // Cartridge port (ff6000-ff9fff)
+ m_cmas = (m_prefix == 0xff) && ((offbase == 0x6000) || (offbase == 0x8000));
+
+ m_gotfirstword = false;
+ }
+}
+
/*
- This method is called by the mapper itself for
- ff4000 (PHYSIC): DSR. ignore
+ Mofetta delivers the GROMCLK. In the 99/4A, this clock is produced by the VDP.
+ Apart from that, Mofetta does not need the CLKOUT.
+*/
+WRITE_LINE_MEMBER( mofetta_device::clock_in )
+{
+ if (state == CLEAR_LINE) // TODO: Correct edge?
+ {
+ m_gromclock_count++;
+ if (m_gromclock_count >=3)
+ {
+ m_gromclk_up = !m_gromclk_up;
+ m_gromclock_count = 0;
+ }
+ }
+}
+
+READ_LINE_MEMBER( mofetta_device::alccs_out )
+{
+ return (m_alccs && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER( mofetta_device::gromclk_out )
+{
+ return m_gromclk_up? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER( mofetta_device::rom1cs_out )
+{
+ return (m_rom1cs && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
+}
+READ_LINE_MEMBER( mofetta_device::rom1am_out )
+{
+ return (m_rom1am && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER( mofetta_device::rom1al_out )
+{
+ return (m_rom1al && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER( mofetta_device::prcs_out )
+{
+ return (m_prcs && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
+}
+
+READ_LINE_MEMBER( mofetta_device::cmas_out )
+{
+ return (m_cmas && m_pmemen)? ASSERT_LINE : CLEAR_LINE;
+}
+
+/*
+ Asserted when a PEB access occurs
*/
-WRITE8_MEMBER( mainboard8_device::write )
+READ_LINE_MEMBER( mofetta_device::dbc_out )
+{
+ return (m_lasreq || m_cmas || m_rom1cs || m_skdrcs || !m_pmemen)? CLEAR_LINE : ASSERT_LINE;
+}
+
+WRITE8_MEMBER(mofetta_device::cruwrite)
{
- if ((offset & 0xffe000)==0xff4000)
+ if ((offset & 0xff00)==0x2700)
{
- if (m_hexbus_selected)
+ if ((offset & 0x0002)!=0)
{
- if ((offset & 0x1ff0)==0x1ff0)
- {
- m_oso->write(space, (offset>>1) & 0x0003, data);
- }
- else
- {
- logerror("%s: Write access to Hexbus DSR address %06x ignored\n", tag(), offset);
- }
+ // SWRST (Software reset)
+ // Value seems to be irrelevant
+ if (TRACE_CRU) logerror("Doing a software reset by SBO 2702\n");
+ m_mainboard->reset_console(ASSERT_LINE);
+ m_mainboard->reset_console(CLEAR_LINE);
}
else
{
- if (m_dsr_selected)
- {
- logerror("%s: Write access to internal DSR address %06x ignored\n", tag(), offset);
- }
- else
- {
- logerror("%s: Write access to unmapped DSR space at address %06x ignored\n", tag(), offset);
- }
+ m_txspg = (data!=0); // CRU>2700
+ if (TRACE_CRU) logerror("Turning %s CRU>2700\n", m_txspg? "on" : "off");
}
}
else
{
- if (((offset & 0xfff0)==0xf870 && m_CRUS==false)||(((offset & 0xfff0)==0x8810 && m_CRUS==true)))
+ if ((offset & 0xff00)==0x1700)
{
- mapwrite(offset, data);
+ m_alcpg = (data!=0); // CRU>1700
+ if (TRACE_CRU) logerror("Turning %s CRU>1700\n", m_alcpg? "on" : "off");
}
}
}
/*
- Reconfigure mapper. Writing to this address copies the values in the
- SRAM into the mapper and vice versa.
- Format:
- 0000 bbbl; bbb=bank, l=load
-
- TODO: Emulate properly, making use of HOLD
+ Setting or clearing the MSAST line.
*/
-void mainboard8_device::mapwrite(int offset, UINT8 data)
+WRITE_LINE_MEMBER( mofetta_device::msast_in )
{
- if ((data & 0xf0)==0x00)
+ if (state == ASSERT_LINE)
{
- int bankindx = (data & 0x0e)>>1;
- if (data & 1)
+ if (m_msast == CLEAR_LINE) // Leading edge
{
- if (TRACE_MAP) logerror("%s: load mapper from SRAM, bank %d\n", tag(), bankindx);
- // Load from SRAM
- // In reality the CPU is put on HOLD during this transfer
- for (int i=0; i < 16; i++)
- {
- int ptr = (bankindx << 6);
- m_pas_offset[i] = (m_sram[(i<<2) + ptr] << 24) | (m_sram[(i<<2)+ ptr+1] << 16)
- | (m_sram[(i<<2) + ptr+2] << 8) | (m_sram[(i<<2) + ptr+3]);
- if (TRACE_MAP) logerror("%s: load %d=%08x\n", tag(), i, m_pas_offset[i]);
- }
- }
- else
- {
- if (TRACE_MAP) logerror("%s: store mapper to SRAM, bank %d\n", tag(), bankindx);
- // Store in SRAM
- for (int i=0; i < 16; i++)
- {
- int ptr = (bankindx << 6);
- m_sram[(i<<2) + ptr] = (m_pas_offset[i] >> 24)& 0xff;
- m_sram[(i<<2) + ptr +1] = (m_pas_offset[i] >> 16)& 0xff;
- m_sram[(i<<2) + ptr +2] = (m_pas_offset[i] >> 8)& 0xff;
- m_sram[(i<<2) + ptr +3] = (m_pas_offset[i])& 0xff;
- if (TRACE_MAP) logerror("%s: save %d=%08x\n", tag(), i, m_pas_offset[i]);
- }
+ m_gotfirstword = true; // Process first word
+ // We now have the first part, containing the flags and the upper byte.
+ m_prefix = m_address_latch & 0xff;
}
}
+ // TODO: Evaluate the first three bits
+ m_msast = (line_state)state;
}
-/***************************************************************************
- Lookup methods.
-***************************************************************************/
+WRITE_LINE_MEMBER( mofetta_device::pmemen_in )
+{
+ m_pmemen = (state==ASSERT_LINE);
+}
-bool mainboard8_device::access_logical_r(address_space& space, offs_t offset, UINT8 *value, UINT8 mem_mask )
+WRITE_LINE_MEMBER( mofetta_device::lascs_in )
{
- bool found = false;
- logically_addressed_device *ldev = m_logcomp.first();
- bus8z_device *bdev;
+ m_lasreq = (state==ASSERT_LINE);
+}
- if (TRACE_DETAIL) logerror("%s: offset=%04x; CRUS=%d, PTGEN=%d\n", tag(), offset, m_CRUS? 1:0, m_PTGE? 0:1);
- while (ldev != nullptr)
- {
- if (TRACE_DETAIL) logerror("%s: checking node=%s\n", tag(), ldev->m_config->name);
- // Check the mode
- if (((ldev->m_config->mode == NATIVE) && (m_CRUS==false))
- || ((ldev->m_config->mode == TI99EM) && (m_CRUS==true))
- || ((ldev->m_config->mode == PATGEN) && (m_PTGE==true)))
- {
- if ((offset & ldev->m_config->address_mask)==ldev->m_config->select_pattern)
- {
- switch (ldev->m_kind)
- {
- case MAP8_SRAM:
- *value = m_sram[offset & ~ldev->m_config->address_mask];
- if (TRACE_MEM) logerror("%s: (SRAM) %04x -> %02x\n", tag(), offset, *value);
- break;
- case MAP8_ROM0:
- // Starts at 0000
- *value = m_rom0[offset & ~ldev->m_config->address_mask];
- if (TRACE_MEM) logerror("%s: (ROM0) %04x -> %02x\n", tag(), offset, *value);
- break;
- case MAP8_DEV:
- // device
- bdev = static_cast<bus8z_device*>(ldev->m_device);
- bdev->readz(space, offset, value, mem_mask);
- if (TRACE_MEM) logerror("%s: (dev %s) %04x -> %02x\n", tag(), ldev->m_config->name, offset, *value);
- break;
- default:
- if (TRACE_MEM) logerror("%s: Invalid kind for read access: %d\n", tag(), ldev->m_kind);
- }
- found = true;
- if (ldev->m_config->stop==STOP) break;
- }
- }
- ldev = ldev->m_next;
- }
- return found;
+WRITE_LINE_MEMBER( mofetta_device::skdrcs_in )
+{
+ m_skdrcs = (state==ASSERT_LINE);
}
-bool mainboard8_device::access_logical_w(address_space& space, offs_t offset, UINT8 data, UINT8 mem_mask )
+void mofetta_device::device_start()
{
- bool found = false;
- logically_addressed_device *ldev = m_logcomp.first();
- bus8z_device *bdev;
+ logerror("Starting\n");
+ m_mainboard = downcast<mainboard8_device*>(owner());
+}
- while (ldev != nullptr)
- {
- // Check the mode
- if (((ldev->m_config->mode == NATIVE) && (m_CRUS==false))
- || ((ldev->m_config->mode == TI99EM) && (m_CRUS==true))
- || ((ldev->m_config->mode == PATGEN) && (m_PTGE==true)))
- {
- if ((offset & ldev->m_config->address_mask)==(ldev->m_config->select_pattern | ldev->m_config->write_select))
- {
- switch (ldev->m_kind)
- {
- case MAP8_SRAM:
- m_sram[offset & ~ldev->m_config->address_mask] = data;
- if (TRACE_MEM) logerror("%s: (SRAM) %04x <- %02x\n", tag(), offset, data);
- break;
- case MAP8_ROM0:
- if (TRACE_MEM) logerror("%s: (ROM0) %04x <- %02x (ignored)\n", tag(), offset, data);
- break;
- case MAP8_DEV:
- // device
- bdev = static_cast<bus8z_device*>(ldev->m_device);
- bdev->write(space, offset, data, mem_mask);
- if (TRACE_MEM) logerror("%s: (dev %s) %04x <- %02x\n", tag(), ldev->m_config->name, offset, data);
- break;
- default:
- if (TRACE_MEM) logerror("%s: Invalid kind for write access: %d\n", tag(), ldev->m_kind);
- }
- found = true;
- if (ldev->m_config->stop==STOP) break;
- }
- }
- ldev = ldev->m_next;
- }
- return found;
+void mofetta_device::device_reset()
+{
+ m_gotfirstword = false;
+ m_alcpg = false;
+ m_txspg = false;
+ m_prefix = 0;
+}
+
+
+const device_type MOFETTA = &device_creator<mofetta_device>;
+
+/***************************************************************************
+
+ ==============================
+ Mapper (codename "Amigo")
+ ==============================
+
+ Unfortunately, we do not have logic diagrams for Amigo, so we have to
+ guess how it is actually working.
+
+ Initial setting of mapper (as defined in the power-up routine, TI-99/4A mode)
+
+ 0 00ff0000 -> Unmapped; logical address 0000...0fff = ROM0
+ 1 00ff0000 -> Unmapped; logical address 1000...1fff = ROM0
+ 2 00000800 -> DRAM; 2000 = 000800, 2fff = 0017ff
+ 3 00001800 -> DRAM; 3000 = 001800, 3fff = 0027ff
+ 4 00ff4000 -> DSR space (internal / ioport)
+ 5 00ff5000 -> DSR space (internal / ioport)
+ 6 00ff6000 -> Cartridge space (6000..6fff)
+ 7 00ff7000 -> Cartridge space (7000..7fff)
+ 8 00ff0000 -> Unmapped; device ports (VDP) and SRAM
+ 9 00ff0000 -> Unmapped; device ports (Speech, GROM)
+ A 00002800 -> DRAM; a000 = 002800, afff = 0037ff
+ B 00003800 -> DRAM; b000 = 003800, bfff = 0047ff
+ C 00004800 -> DRAM; c000 = 004800, cfff = 0057ff
+ D 00005800 -> DRAM; d000 = 005800, dfff = 0067ff
+ E 00006800 -> DRAM; e000 = 006800, efff = 0077ff
+ F 00007800 -> DRAM; f000 = 007800, ffff = 0087ff
+
+ Format of map table entry
+
+ +--+---+---+---+---+---+---+---+ +-----------+ +----------+ +---------+
+ | W| X | R | 0 | 0 | 0 | 0 | 0 | | Upper (8) | | High (8) | | Low (8) |
+ +--+---+---+---+---+---+---+---+ +-----------+ +----------+ +---------+
+
+ W: Write protection if set to 1
+ X: Execute protection if set to 1
+ R: Read protection if set to 1
+
+ When a protection violation occurs, the tms9901 INT1* pin is pulled low
+ (active). The pin remains low until the mapper status register is read.
+
+ Address handling
+ ----------------
+ Physical address is (Upper * 2^16) + (High * 2^8) + Low
+
+ The mapper calculates the actual physical address by looking up the
+ table entry from the first four bits of the logical address and then
+ *adding* the remaining 12 bits of the logical address on the map value.
+
+ The value 0xff0000 is used to indicate a non-mapped area.
+
+ Mapper control register
+ -----------------------
+ The mapper control register is used to initiate a map load/save operation.
+
+ +---+---+---+---+---+---+---+---+
+ | 0 | 0 | 0 | 0 | Map File | RW|
+ +---+---+---+---+---+---+---+---+
+
+ The map file is a number from 0-7 indicating the set of map values for the
+ operation, which means the location in SRAM where the next 64 values are
+ loaded from or stored into.
+
+ RW = 1: load from SRAM into mapper
+ RW = 0: store from mapper into SRAM
+
+ When read, the mapper register returns the violation flags:
+ +---+---+---+---+---+---+---+---+
+ | W | X | R | 0 | 0 | 0 | 0 | 0 |
+ +---+---+---+---+---+---+---+---+
+
+***************************************************************************/
+
+amigo_device::amigo_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+: device_t(mconfig, AMIGO, "Address space mapper", tag, owner, clock, "ti998_amigo", __FILE__),
+ m_logical_space(true),
+ m_crus(ASSERT_LINE)
+{
}
+enum
+{
+ IDLE = 0,
+ CREATE_PADDR,
+ ADDR_MSW,
+ ADDR_LSW,
+ SRAMLOAD,
+ SRAMSAVE
+};
-void mainboard8_device::access_physical_r( address_space& space, offs_t pas_address, UINT8 *value, UINT8 mem_mask )
+/*
+ Incoming READY line (SRDY)
+*/
+WRITE_LINE_MEMBER( amigo_device::srdy_in )
{
- physically_addressed_device *pdev = m_physcomp.first();
- bus8z_device *bdev;
+ if (TRACE_READY) logerror("Incoming SRDY = %d\n", state);
+ m_srdy = (line_state)state;
- while (pdev != nullptr)
+ // If the access is going to logical space, pass through the READY line
+ if (m_logical_space)
{
- if ((pas_address & pdev->m_config->address_mask)==pdev->m_config->select_pattern)
- {
- switch (pdev->m_kind)
- {
- case MAP8_DRAM:
- *value = m_dram[pas_address & ~pdev->m_config->address_mask];
- if (TRACE_MEM) logerror("%s: (DRAM) %06x -> %02x\n", tag(), pas_address, *value);
- break;
- case MAP8_ROM1A0:
- // Starts at 0000 in the image, 8K
- *value = m_rom1[pas_address & 0x1fff];
- if (TRACE_MEM) logerror("%s: (ROM) %06x -> %02x\n", tag(), pas_address, *value);
- break;
- case MAP8_ROM1C0:
- // Starts at 2000 in the image, 8K
- *value = m_rom1[0x2000 | (pas_address & 0x1fff)];
- if (TRACE_MEM) logerror("%s: (ROM) %06x -> %02x\n", tag(), pas_address, *value);
- break;
- case MAP8_PCODE:
- *value = m_pcode[pas_address & 0x3fff];
- if (TRACE_MEM) logerror("%s: (PCODE) %06x -> %02x\n", tag(), pas_address, *value);
- break;
- case MAP8_INTS:
- // Interrupt sense
- logerror("%s: ILSENSE not implemented.\n", tag());
- break;
- case MAP8_DEV:
- // devices
- bdev = static_cast<bus8z_device*>(pdev->m_device);
- bdev->readz(space, pas_address, value, mem_mask);
- if (TRACE_MEM) logerror("%s: (dev %s) %06x -> %02x\n", tag(), pdev->m_config->name, pas_address, *value);
- break;
- default:
- logerror("%s: Invalid kind for physical read access: %d\n", tag(), pdev->m_kind);
- }
- if (pdev->m_config->stop==STOP) break;
- }
- pdev = pdev->m_next;
+ if (TRACE_CPURY) logerror("Setting CPURY = %d (SRDY)\n", m_ready_out);
+ m_ready_out = m_srdy;
}
}
-void mainboard8_device::access_physical_w( address_space& space, offs_t pas_address, UINT8 data, UINT8 mem_mask )
+WRITE_LINE_MEMBER( amigo_device::memen_in )
{
- physically_addressed_device *pdev = m_physcomp.first();
- bus8z_device *bdev;
+ m_memen = (state==ASSERT_LINE);
+}
- while (pdev != nullptr)
- {
- if ((pas_address & pdev->m_config->address_mask)==(pdev->m_config->select_pattern | pdev->m_config->write_select))
- {
- switch (pdev->m_kind)
- {
- case MAP8_DRAM:
- m_dram[pas_address & ~pdev->m_config->address_mask] = data;
- if (TRACE_MEM) logerror("%s: (DRAM) %06x <- %02x\n", tag(), pas_address, data);
- break;
- case MAP8_ROM1A0:
- case MAP8_ROM1C0:
- if (TRACE_MEM) logerror("%s: (ROM1) %06x <- %02x (ignored)\n", tag(), pas_address, data);
- break;
- case MAP8_PCODE:
- if (TRACE_MEM) logerror("%s: (PCODE) %06x <- %02x (ignored)\n", tag(), pas_address, data);
- break;
- case MAP8_INTS:
- // Interrupt sense
- logerror("%s: write to ilsense ignored\n", tag());
- break;
- case MAP8_DEV:
- // devices
- bdev = static_cast<bus8z_device*>(pdev->m_device);
- if (TRACE_MEM) logerror("%s: (dev %s) %06x <- %02x\n", tag(), pdev->m_config->name, pas_address, data);
- bdev->write(space, pas_address, data, mem_mask);
- break;
- default:
- logerror("%s: Invalid kind for physical write access: %d\n", tag(), pdev->m_kind);
- }
- if (pdev->m_config->stop==STOP) break;
- }
- pdev = pdev->m_next;
- }
+/*
+ Polled from the mainboard
+*/
+READ_LINE_MEMBER( amigo_device::cpury_out )
+{
+ return m_ready_out;
}
/*
- The mapper is connected to the clock line in order to operate
- the wait state counter.
+ Polled from the mainboard
*/
-void mainboard8_device::clock_in(int clock)
+READ_LINE_MEMBER( amigo_device::sramcs_out )
{
- if (clock==ASSERT_LINE && m_waitcount!=0)
- {
- m_waitcount--;
- if (m_waitcount==0) m_ready(ASSERT_LINE);
- }
+ return m_sram_accessed && m_memen? ASSERT_LINE : CLEAR_LINE;
}
+/*
+ SKDRCS line (maybe "Sixty-four Kilobyte DRam Chip Select"). We assume that
+ Amigo asserts the select line not before the whole address was written.
+ This is actually more than needed because we only have 64K DRAM (which
+ would only need a 16 bit address), and Amigo itself selects it.
+*/
+READ_LINE_MEMBER( amigo_device::skdrcs_out )
+{
+ return m_dram_accessed && (m_amstate == IDLE) && m_memen? ASSERT_LINE : CLEAR_LINE;
+}
-/***************************************************************************
- DEVICE LIFECYCLE FUNCTIONS
-***************************************************************************/
/*
- We need to do all of the configuration in device_start since we don't have all
- required links earlier.
+ Incoming CRUS line. Needed to set the mapper config addresses.
+*/
+WRITE_LINE_MEMBER( amigo_device::crus_in )
+{
+ m_crus = (line_state)state;
+}
- Note that device_reset is too late; the initial context switch occurs earlier.
+/*
+ Incoming LASCS line.
*/
-void mainboard8_device::device_start()
+WRITE_LINE_MEMBER( amigo_device::lascs_in )
{
- logerror("%s: Starting mapper\n", tag());
+ m_logical_space = (state==ASSERT_LINE);
+}
+
+/*
+ The logical address bus has been set. The Amigo chip now has to map this
+ address to a physical address. There are three phases (3 clock ticks):
+ 1. Sample the logical address lines, determine the map register
+ (first four bits), create the physical address by adding the remaining
+ 12 bits and the map register contents
+ 2. Set the physical address bus with the first 16 bits of the physical
+ address. Assert the MSAST line.
+ 3. Set the physical address bus with the second 16 bits of the physical
+ address. Clear the MSAST line. Forward any incoming READY=0 to the CPU.
+*/
+SETOFFSET_MEMBER( amigo_device::set_address )
+{
+ // Check whether the mapper itself is accessed
+ int mapaddr = (m_crus==ASSERT_LINE)? 0x8810 : 0xf870;
+ m_mapper_accessed = ((offset & 0xfff1)==mapaddr);
+
+ // or SRAM
+ int sramaddr = (m_crus==ASSERT_LINE)? 0x8000 : 0xf000;
+ m_sram_accessed = ((offset & 0xf800)==sramaddr);
+
+ m_logical_space |= (m_mapper_accessed || m_sram_accessed);
+
+ // Is the address not in the logical address space?
+ if (!m_logical_space)
+ {
+ if (TRACE_AMIGO) logerror("Amigo decoding; %04x is a physical address.\n", offset);
+ // Build the physical address
+ // The first three bits are the protection bits (Write, Execute, Read)
+ // Theoretically, the addition of the logical address could mess up those
+ // first three bits, but the physical address is only 24 bits wide, so we
+ // have a space of 5 zeros between the protection bits and the address.
+ // We should just clear those five bits after the addition.
+
+ m_physical_address = ((offset & 0x0fff) + m_base_register[(offset >> 12) & 0x000f]) & 0x00ffffff;
- // String values of the pseudo constants, used in the configuration.
- const char *const pseudodev[7] = { SRAMNAME, ROM0NAME, ROM1A0NAME, ROM1C0NAME, DRAMNAME, PCODENAME, INTSNAME };
+ // TODO: Process flags
- const mapper8_config *conf = reinterpret_cast<const mapper8_config *>(static_config());
+ // Is it DRAM?
+ m_dram_accessed = (m_physical_address & 0x00ff0000)==0;
- const mapper8_list_entry *entry = conf->devlist;
- m_ready.resolve_safe();
+ // This takes one clock pulse.
+ m_amstate = CREATE_PADDR;
- m_sram = machine().root_device().memregion(SRAM_TAG)->base();
- m_dram = machine().root_device().memregion(DRAM_TAG)->base();
- m_rom0 = machine().root_device().memregion(ROM0_TAG)->base();
- m_rom1 = machine().root_device().memregion(ROM1_TAG)->base();
- m_pcode = machine().root_device().memregion(PCODEROM_TAG)->base();
+ // Pull down READY
+ m_ready_out = CLEAR_LINE;
+
+ if (TRACE_CPURY) logerror("Setting CPURY = %d (PAS)\n", m_ready_out);
+ }
+ else
+ {
+ // This was a logical space access. Pass through READY.
+ m_dram_accessed = false;
+ m_amstate = IDLE;
+ m_ready_out = m_srdy;
+ if (TRACE_CPURY) logerror("Setting CPURY = %d (LAS)\n", m_ready_out);
+ }
+}
+
+/*
+ Read the mapper status bits
+*/
+READ8_MEMBER( amigo_device::read )
+{
+ // Read the protection status bits and reset them
+ UINT8 value = m_protflag;
+ m_protflag = 0;
+ return value;
+}
- // Clear the lists
- m_logcomp.reset();
- m_physcomp.reset();
+/*
+ Configure the mapper. This is the only reason to write to the AMIGO.
+*/
+WRITE8_MEMBER( amigo_device::write )
+{
+ // Load or save map file
+ if ((data & 0xf0)==0x00)
+ {
+ // Need to HOLD the CPU
+ m_amstate = ((data & 1)==1)? SRAMLOAD : SRAMSAVE;
+ m_sram_address = (data & 0x0e) << 5;
+ m_hold_acknowledged = false;
+ m_basereg = 0;
+ m_mapvalue = 0;
+ m_mainboard->hold_cpu(ASSERT_LINE);
+ }
+ else logerror("Invalid value written to Amigo: %02x\n", data);
+}
- // Now building the list of active devices at this mapper.
- // Coyping partly from datamux.c.
- if ( entry != nullptr )
+WRITE_LINE_MEMBER( amigo_device::clock_in )
+{
+ if (state==CLEAR_LINE)
{
- bool done = false;
- for (int i=0; !done; i++)
+ switch (m_amstate)
{
- if (entry[i].name == nullptr)
- {
- done = true;
- }
- else
- {
- device_t *dev = nullptr;
- mapper8_device_kind kind = MAP8_UNDEF;
-
- for (int j=1; (j < 8) && (kind == MAP8_UNDEF); j++)
- {
- // Pseudo devices are enumerated as 1 ... 6 (see MAP8_SRAM etc.)
- if (strcmp(entry[i].name, pseudodev[j-1])==0) kind = (mapper8_device_kind)j;
- }
- if (kind==MAP8_UNDEF)
- {
- // This entry points to a "real" device, not to a special constant
- kind = MAP8_DEV;
- dev = machine().device(entry[i].name);
- }
- if (kind != MAP8_DEV || dev != nullptr)
- {
- if (entry[i].mode != PHYSIC)
- {
- auto ad = new logically_addressed_device(kind, (device_t*)dev, entry[i]);
- m_logcomp.append(*ad);
- if (TRACE_CONFIG) logerror("%s: Device %s mounted into logical address space.\n", tag(), entry[i].name);
- }
- else
- {
- auto ad = new physically_addressed_device(kind, (device_t*)dev, entry[i]);
- m_physcomp.append(*ad);
- if (TRACE_CONFIG) logerror("%s: Device %s mounted into physical address space.\n", tag(), entry[i].name);
- }
- }
- else
- {
- if (TRACE_CONFIG) logerror("%s: Device %s not found.\n", tag(), entry[i].name);
- }
- }
+ case IDLE:
+ break;
+ case CREATE_PADDR:
+ // Address has been created
+ m_amstate = ADDR_MSW;
+ break;
+ case ADDR_MSW:
+ // Transmit the first word (without the protection bits)
+ m_mainboard->set_paddress((m_physical_address >> 16) & 0x00ff);
+ m_amstate = ADDR_LSW;
+ break;
+ case ADDR_LSW:
+ m_mainboard->msast_in(ASSERT_LINE); // Pulse MSAST
+ m_mainboard->msast_in(CLEAR_LINE);
+ m_mainboard->set_paddress(m_physical_address & 0xffff);
+ m_amstate = IDLE;
+ m_ready_out = m_srdy; // Propagate incoming READY
+ break;
+
+ case SRAMLOAD:
+ if (m_hold_acknowledged) mapper_load();
+ break;
+
+ case SRAMSAVE:
+ if (m_hold_acknowledged) mapper_save();
+ break;
+
+ default:
+ logerror("Invalid state in mapper: %d\n", m_amstate);
}
}
- if (TRACE_CONFIG) logerror("%s: Mapper logical device count = %d\n", tag(), m_logcomp.count());
- if (TRACE_CONFIG) logerror("%s: Mapper physical device count = %d\n", tag(), m_physcomp.count());
+}
- m_dsr_selected = false;
- m_CRUS = true;
- m_PTGE = false;
+void amigo_device::mapper_load()
+{
+ m_mapvalue = (m_mapvalue << 8) | m_sram[m_sram_address++];
- // Clean mapper
- for (auto & elem : m_pas_offset) elem = 0;
+ if ((m_sram_address & 0x03)==0)
+ {
+ if (TRACE_MAP) logerror("Loaded basereg %02d = %08x\n", m_basereg, m_mapvalue);
+ m_base_register[m_basereg++] = m_mapvalue;
+ }
+ if (m_basereg == 16)
+ {
+ m_amstate = IDLE;
+ m_mainboard->hold_cpu(CLEAR_LINE);
+ }
}
-void mainboard8_device::device_reset()
+void amigo_device::mapper_save()
{
- m_dsr_selected = false;
- m_CRUS = true;
- m_PTGE = false;
- m_waitcount = 0;
- m_hexbus_selected = false;
+ if ((m_sram_address & 0x03)==0)
+ {
+ if (m_basereg == 16)
+ {
+ m_amstate = IDLE;
+ m_mainboard->hold_cpu(CLEAR_LINE);
+ return;
+ }
+ else
+ {
+ m_mapvalue = m_base_register[m_basereg];
+ if (TRACE_MAP) logerror("Saving basereg %02d = %08x\n", m_basereg, m_mapvalue);
+ m_basereg++;
+ }
+ }
- // Clean mapper
- for (auto & elem : m_pas_offset) elem = 0;
+ m_sram[m_sram_address++] = (m_mapvalue >> 24) & 0xff;
+ m_mapvalue = m_mapvalue << 8;
+}
- m_ready(ASSERT_LINE);
+WRITE_LINE_MEMBER( amigo_device::holda_in )
+{
+ if (TRACE_MAP) logerror("HOLD acknowledged = %d\n", state);
+ m_hold_acknowledged = (state==ASSERT_LINE);
}
-MACHINE_CONFIG_FRAGMENT( ti998_mainboard )
- MCFG_DEVICE_ADD(OSO_TAG, OSO, 0)
-MACHINE_CONFIG_END
+void amigo_device::device_start()
+{
+ logerror("Starting\n");
+ m_mainboard = downcast<mainboard8_device*>(owner());
+}
-machine_config_constructor mainboard8_device::device_mconfig_additions() const
+void amigo_device::device_reset()
{
- return MACHINE_CONFIG_NAME( ti998_mainboard );
+ m_logical_space = true;
}
-const device_type MAINBOARD8 = &device_creator<mainboard8_device>;
+const device_type AMIGO = &device_creator<amigo_device>;
/***************************************************************************
- Custom chips of the TI-99/8
-
===== OSO: Hexbus interface =====
The Hexbus is a 4-bit peripheral bus with master/slave coordination. Bytes
@@ -858,12 +1909,12 @@ enum
SHSK = 0x01
};
-ti998_oso_device::ti998_oso_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
-: device_t(mconfig, OSO, "OSO Hexbus interface", tag, owner, clock, "ti998_oso", __FILE__), m_data(0), m_status(0), m_control(0), m_xmit(0)
+oso_device::oso_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+: device_t(mconfig, OSO, "Hexbus interface", tag, owner, clock, "oso", __FILE__), m_data(0), m_status(0), m_control(0), m_xmit(0)
{
}
-READ8_MEMBER( ti998_oso_device::read )
+READ8_MEMBER( oso_device::read )
{
int value = 0;
offset &= 0x03;
@@ -871,36 +1922,36 @@ READ8_MEMBER( ti998_oso_device::read )
{
case 0:
// read 5FF8: read data register
- if (TRACE_OSO) logerror("%s: Read data register = %02x\n", tag(), value);
+ if (TRACE_OSO) logerror("Read data register = %02x\n", value);
value = m_data;
break;
case 1:
// read 5FFA: read status register
value = m_status;
- if (TRACE_OSO) logerror("%s: Read status %02x\n", tag(), value);
+ if (TRACE_OSO) logerror("Read status %02x\n", value);
break;
case 2:
// read 5FFC: read control register
value = m_control;
- if (TRACE_OSO) logerror("%s: Read control register = %02x\n", tag(), value);
+ if (TRACE_OSO) logerror("Read control register = %02x\n", value);
break;
case 3:
// read 5FFE: read transmit register
value = m_xmit;
- if (TRACE_OSO) logerror("%s: Read transmit register = %02x\n", tag(), value);
+ if (TRACE_OSO) logerror("Read transmit register = %02x\n", value);
break;
}
return value;
}
-WRITE8_MEMBER( ti998_oso_device::write )
+WRITE8_MEMBER( oso_device::write )
{
offset &= 0x03;
switch (offset)
{
case 0:
// write 5FF8: write transmit register
- if (TRACE_OSO) logerror("%s: Write transmit register %02x\n", tag(), data);
+ if (TRACE_OSO) logerror("Write transmit register %02x\n", data);
m_xmit = data;
// We set the status register directly in order to prevent lock-ups
// until we have a complete Hexbus implementation
@@ -908,169 +1959,20 @@ WRITE8_MEMBER( ti998_oso_device::write )
break;
case 1:
// write 5FFA: write control register
- if (TRACE_OSO) logerror("%s: Write control register %02x\n", tag(), data);
+ if (TRACE_OSO) logerror("Write control register %02x\n", data);
m_control = data;
break;
default:
// write 5FFC, 5FFE: undefined
- if (TRACE_OSO) logerror("%s: Invalid write on %04x: %02x\n", tag(), (offset<<1) | 0x5ff0, data);
+ if (TRACE_OSO) logerror("Invalid write on %04x: %02x\n", (offset<<1) | 0x5ff0, data);
break;
}
}
-void ti998_oso_device::device_start()
+void oso_device::device_start()
{
+ logerror("Starting\n");
m_status = m_xmit = m_control = m_data = 0;
}
-const device_type OSO = &device_creator<ti998_oso_device>;
-
-
-// ========================================================================
-
-/****************************************************************************
-
- TI-99/8 Speech synthesizer subsystem
-
- The TI-99/8 contains a speech synthesizer inside the console, so we cannot
- reuse the spchsyn implementation of the P-Box speech synthesizer.
- Accordingly, this is not a ti_expansion_card_device.
-
- For comments on real timing see ti99/spchsyn.c
-
- Note that before the REAL_TIMING can be used we must first establish
- the set_address logic in 998board.
-
-*****************************************************************************/
-
-#define TMS5220_ADDRESS_MASK 0x3FFFFUL /* 18-bit mask for tms5220 address */
-#define SPEECHSYN_TAG "speechsyn"
-#define REAL_TIMING 0
-
-ti998_spsyn_device::ti998_spsyn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
-: bus8z_device(mconfig, SPEECH8, "TI-99/8 Onboard Speech synthesizer", tag, owner, clock, "ti998_speech", __FILE__), m_vsp(nullptr),
- m_ready(*this)
-{
-}
-
-/*
- Memory read
-*/
-#if REAL_TIMING
-// ====== This is the version with real timing =======
-READ8Z_MEMBER( ti998_spsyn_device::readz )
-{
- m_vsp->wsq_w(TRUE);
- m_vsp->rsq_w(FALSE);
- *value = m_vsp->read(offset) & 0xff;
- if (TRACE_SPEECH) logerror("%s: read value = %02x\n", tag(), *value);
-}
-
-/*
- Memory write
-*/
-WRITE8_MEMBER( ti998_spsyn_device::write )
-{
- m_vsp->rsq_w(m_vsp, TRUE);
- m_vsp->wsq_w(m_vsp, FALSE);
- if (TRACE_SPEECH) logerror("%s: write value = %02x\n", tag(), data);
- m_vsp->write(offset, data);
-}
-
-#else
-// ====== This is the version without real timing =======
-
-READ8Z_MEMBER( ti998_spsyn_device::readz )
-{
- machine().device("maincpu")->execute().adjust_icount(-(18+3)); /* this is just a minimum, it can be more */
- *value = m_vsp->status_r(space, offset, 0xff) & 0xff;
- if (TRACE_SPEECH) logerror("%s: read value = %02x\n", tag(), *value);
-}
-
-/*
- Memory write
-*/
-WRITE8_MEMBER( ti998_spsyn_device::write )
-{
- machine().device("maincpu")->execute().adjust_icount(-(54+3)); /* this is just an approx. minimum, it can be much more */
-
- /* RN: the stupid design of the tms5220 core means that ready is cleared */
- /* when there are 15 bytes in FIFO. It should be 16. Of course, if */
- /* it were the case, we would need to store the value on the bus, */
- /* which would be more complex. */
- if (!m_vsp->readyq_r())
- {
- attotime time_to_ready = attotime::from_double(m_vsp->time_to_ready());
- int cycles_to_ready = machine().device<cpu_device>("maincpu")->attotime_to_cycles(time_to_ready);
- if (TRACE_SPEECH && TRACE_DETAIL) logerror("%s: time to ready: %f -> %d\n", tag(), time_to_ready.as_double(), (int) cycles_to_ready);
-
- machine().device("maincpu")->execute().adjust_icount(-cycles_to_ready);
- machine().scheduler().timer_set(attotime::zero, FUNC_NULL);
- }
- if (TRACE_SPEECH) logerror("%s: write value = %02x\n", tag(), data);
- m_vsp->data_w(space, offset, data);
-}
-#endif
-
-/**************************************************************************/
-
-WRITE_LINE_MEMBER( ti998_spsyn_device::speech8_ready )
-{
- // The TMS5200 implementation uses TRUE/FALSE, not ASSERT/CLEAR semantics
- m_ready((state==0)? ASSERT_LINE : CLEAR_LINE);
- if (TRACE_SPEECH) logerror("%s: READY = %d\n", tag(), (state==0));
-
-#if REAL_TIMING
- // Need to do that here (see explanations in spchsyn.c)
- if (state==0)
- {
- m_vsp->rsq_w(TRUE);
- m_vsp->wsq_w(TRUE);
- }
-#endif
-}
-
-void ti998_spsyn_device::device_start()
-{
- m_ready.resolve_safe();
- m_vsp = subdevice<tms5220_device>(SPEECHSYN_TAG);
- speechrom_device* mem = subdevice<speechrom_device>("vsm");
- mem->set_reverse_bit_order(true);
-}
-
-void ti998_spsyn_device::device_reset()
-{
- if (TRACE_SPEECH) logerror("%s: reset\n", tag());
-}
-
-// Unlike the TI-99/4A, the 99/8 uses the CD2501ECD
-// The CD2501ECD is a tms5200/cd2501e with the rate control from the tms5220c added in.
-// (it's probably actually a tms5220c die with the cd2501e/tms5200 lpc rom masked onto it)
-MACHINE_CONFIG_FRAGMENT( ti998_speech )
- MCFG_DEVICE_ADD("vsm", SPEECHROM, 0)
-
- MCFG_SPEAKER_STANDARD_MONO("mono")
- MCFG_SOUND_ADD(SPEECHSYN_TAG, CD2501ECD, 640000L)
- MCFG_TMS52XX_READYQ_HANDLER(WRITELINE(ti998_spsyn_device, speech8_ready))
- MCFG_TMS52XX_SPEECHROM("vsm")
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
-MACHINE_CONFIG_END
-
-/* Verified on a real machine: TI-99/8 uses the same speech rom contents
- as the TI speech synthesizer. */
-ROM_START( ti998_speech )
- ROM_REGION(0x8000, "vsm", 0)
- ROM_LOAD("cd2325a.vsm", 0x0000, 0x4000, CRC(1f58b571) SHA1(0ef4f178716b575a1c0c970c56af8a8d97561ffe))
- ROM_LOAD("cd2326a.vsm", 0x4000, 0x4000, CRC(65d00401) SHA1(a367242c2c96cebf0e2bf21862f3f6734b2b3020))
-ROM_END
-
-machine_config_constructor ti998_spsyn_device::device_mconfig_additions() const
-{
- return MACHINE_CONFIG_NAME( ti998_speech );
-}
-
-const rom_entry *ti998_spsyn_device::device_rom_region() const
-{
- return ROM_NAME( ti998_speech );
-}
-const device_type SPEECH8 = &device_creator<ti998_spsyn_device>;
+const device_type OSO = &device_creator<oso_device>;
diff --git a/src/devices/bus/ti99x/998board.h b/src/devices/bus/ti99x/998board.h
index 9231d9be647..0a1d1523db7 100644
--- a/src/devices/bus/ti99x/998board.h
+++ b/src/devices/bus/ti99x/998board.h
@@ -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
+ SGMSEL = 1,
+ TSGSEL = 2,
+ P8GSEL = 4,
+ P3GSEL = 8,
+ VIDSEL = 16
};
-struct mapper8_list_entry
+/*
+ Wait state generator (part of Vaquerro)
+*/
+class waitstate_generator
{
- 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
-};
+public:
+ 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);
+
+ 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();
-#define MAPPER8_CONFIG(name) \
- const mapper8_config(name) =
+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;
+};
-#define MCFG_MAINBOARD8_READY_CALLBACK(_write) \
- devcb = &mainboard8_device::set_ready_wr_callback(*device, DEVCB_##_write);
+class grom_waitstate_generator : public waitstate_generator
+{
+public:
+ void ready_in(line_state ready) override;
+ void clock_in(line_state clkout) override;
+};
-struct mapper8_config
+class video_waitstate_generator : public waitstate_generator
{
- const mapper8_list_entry *devlist;
+public:
+ void ready_in(line_state ready) override { };
+ void clock_in(line_state clkout) override;
};
/*
- Device list of the mapper.
+ Custom chip: Vaquerro
*/
-class logically_addressed_device
+class vaquerro_device : public device_t
{
- 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) { };
+ 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:
- 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;
+ // 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;
};
/*
- Device list of the mapper.
+ Custom chip: Mofetta
*/
-class physically_addressed_device
+class mofetta_device : public device_t
{
- friend class simple_list<physically_addressed_device>;
- friend class mainboard8_device;
+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:
- 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) { };
+ 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:
- 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;
+
+ // 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,139 +391,176 @@ 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
+class mainboard8_device : public device_t
{
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) { };
+ mainboard8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
- DECLARE_WRITE_LINE_MEMBER( speech8_ready );
+ // Memory space
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+ DECLARE_SETOFFSET_MEMBER( setoffset );
+
+ // I/O space
+ DECLARE_READ8Z_MEMBER( crureadz );
+ DECLARE_WRITE8_MEMBER( cruwrite );
+
+ // 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_WRITE_LINE_MEMBER( holda_line );
+
+ 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);
+ }
+
+ 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:
- 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;
+ void device_start(void) override;
+ void device_reset(void) override;
+ 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
+ // Propagates the end of the memory cycle
+ void cycle_end();
- // Ready line to the CPU
- devcb_write_line m_ready;
-};
+ // Original logical address.
+ int m_logical_address;
-#define MCFG_TISPEECH8_ADD(_tag, _conf) \
- MCFG_DEVICE_ADD(_tag, TI99_SPEECH8, 0) \
- MCFG_DEVICE_CONFIG(_conf)
+ // 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;
-/*
- Main class
-*/
-class mainboard8_device : public bus8z_device
-{
-public:
- mainboard8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // Indicates that a byte is waiting on the data bus (see m_latched_data)
+ bool m_pending_write;
- 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); }
+ // 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;
- DECLARE_READ8_MEMBER( readm); // used from address map
- DECLARE_WRITE8_MEMBER( writem ); // used from address map
+ // Hold the level of the GROMCLK line
+ int m_gromclk;
- DECLARE_READ8Z_MEMBER( readz ) override;
- DECLARE_WRITE8_MEMBER( write ) override;
+ // Selecting GROM libraries
+ void select_groms();
- DECLARE_READ8Z_MEMBER(crureadz);
- DECLARE_WRITE8_MEMBER(cruwrite);
+ // Previous select state
+ int m_prev_grom;
- void CRUS_set(bool state);
- void PTGE_set(bool state);
+ // Ready states
+ bool m_speech_ready;
+ bool m_sound_ready;
+ bool m_pbox_ready;
- void clock_in(int state);
+ // Holds the A14 address line state. We need this for the clock_in method.
+ bool m_A14_set;
-protected:
- void device_start(void) override;
- void device_reset(void) override;
- machine_config_constructor device_mconfig_additions() const override;
+ // 99/4A compatibility mode. Name is taken from the spec. If asserted, 99/4A compatibility is active.
+ line_state m_crus;
-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);
+ // 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;
+
+ // Hold line to the main system
+ devcb_write_line m_hold_line;
- // All devices that are attached to the 24-bit mapped address bus.
- simple_list<physically_addressed_device> m_physcomp;
+ // Custom chips
+ required_device<vaquerro_device> m_vaquerro;
+ required_device<mofetta_device> m_mofetta;
+ required_device<amigo_device> m_amigo;
+ required_device<oso_device> m_oso;
- // Select bit for the internal DSR.
- bool m_dsr_selected;
+ // Debugging
+ line_state m_last_ready;
- // Select bit for the Hexbus DSR.
- bool m_hexbus_selected;
+ // Video processor
+ tms9118_device* m_video;
- // 99/4A compatibility mode. Name is taken from the spec. If 1, 99/4A compatibility is active.
- bool m_CRUS;
+ // Sound generator
+ sn76496_base_device* m_sound;
- // 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;
+ // Speech processor
+ cd2501ecd_device* m_speech;
- // Counter for the wait states.
- int m_waitcount;
+ // System GROM library
+ tmc0430_device* m_sgrom[3];
- // Address mapper registers. Each offset is selected by the first 4 bits
- // of the logical address.
- UINT32 m_pas_offset[16];
+ // Text-to-speech GROM library
+ tmc0430_device* m_tsgrom[8];
- // SRAM area of the system. Directly connected to the address decoder.
- UINT8 *m_sram;
+ // Pascal 8 GROM library
+ tmc0430_device* m_p8grom[8];
- // DRAM area of the system. Connected to the mapped address bus.
- UINT8 *m_dram;
+ // Pascal 3 GROM library
+ tmc0430_device* m_p3grom[3];
- // ROM area of the system. Directly connected to the logical address decoder.
- UINT8 *m_rom0;
+ // Gromport (cartridge port)
+ gromport_device* m_gromport;
- // ROM area of the system. Directly connected to the physical address decoder.
- UINT8 *m_rom1;
+ // Peripheral box
+ peribox_device* m_peb;
- // P-Code ROM area of the system. Directly connected to the physical address decoder.
- UINT8 *m_pcode;
+ // Memory
+ std::unique_ptr<UINT8[]> m_sram;
+ std::unique_ptr<UINT8[]> m_dram;
- // Custom chips
- required_device<ti998_oso_device> m_oso;
+ // 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
diff --git a/src/devices/bus/ti99x/datamux.cpp b/src/devices/bus/ti99x/datamux.cpp
index 1b8ec8de02f..da971c4ceec 100644
--- a/src/devices/bus/ti99x/datamux.cpp
+++ b/src/devices/bus/ti99x/datamux.cpp
@@ -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.
+
+ 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);
- return ((hbyte<<8) | m_latch) & mem_mask;
+ 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)" )
diff --git a/src/devices/bus/ti99x/datamux.h b/src/devices/bus/ti99x/datamux.h
index 604dfb2e62f..eaad45b7238 100644
--- a/src/devices/bus/ti99x/datamux.h
+++ b/src/devices/bus/ti99x/datamux.h
@@ -15,54 +15,14 @@
#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
*/
class ti99_datamux_device : public device_t
@@ -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
diff --git a/src/devices/bus/ti99x/genboard.cpp b/src/devices/bus/ti99x/genboard.cpp
index 9d6aeef7e76..1abdd7c6762 100644
--- a/src/devices/bus/ti99x/genboard.cpp
+++ b/src/devices/bus/ti99x/genboard.cpp
@@ -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);
diff --git a/src/devices/bus/ti99x/genboard.h b/src/devices/bus/ti99x/genboard.h
index 2248c64f9fe..8f49cb6906e 100644
--- a/src/devices/bus/ti99x/genboard.h
+++ b/src/devices/bus/ti99x/genboard.h
@@ -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;
diff --git a/src/devices/bus/ti99x/grom.cpp b/src/devices/bus/ti99x/grom.cpp
deleted file mode 100644
index 1ecb0168d80..00000000000
--- a/src/devices/bus/ti99x/grom.cpp
+++ /dev/null
@@ -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>;
diff --git a/src/devices/bus/ti99x/grom.h b/src/devices/bus/ti99x/grom.h
deleted file mode 100644
index a3129b6997f..00000000000
--- a/src/devices/bus/ti99x/grom.h
+++ /dev/null
@@ -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
diff --git a/src/devices/bus/ti99x/gromport.cpp b/src/devices/bus/ti99x/gromport.cpp
index 33ef82ae2a7..9a836f970d1 100644
--- a/src/devices/bus/ti99x/gromport.cpp
+++ b/src/devices/bus/ti99x/gromport.cpp
@@ -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,48 +1554,44 @@ WRITE_LINE_MEMBER( ti99_cartridge_device::ready_line )
m_connector->ready_line(state);
}
-void ti99_cartridge_device::device_config_complete()
+WRITE_LINE_MEMBER( ti99_cartridge_device::romgq_line )
{
- update_names();
- m_softlist = false;
- m_connector = static_cast<ti99_cartridge_connector_device*>(owner());
+ if (m_pcb != nullptr)
+ {
+ m_pcb->romgq_line(state);
+ m_readrom = state;
+ }
}
-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)
+/*
+ Combined select lines
+*/
+WRITE8_MEMBER(ti99_cartridge_device::set_gromlines)
{
- false, 5, CARTGROM_TAG, 0x4000, 0x1800, GROMFREQ
-};
-static GROM_CONFIG(grom6_config)
+ if (m_pcb != nullptr) m_pcb->set_gromlines(space, offset, data);
+}
+
+WRITE_LINE_MEMBER(ti99_cartridge_device::gclock_in)
{
- false, 6, CARTGROM_TAG, 0x6000, 0x1800, GROMFREQ
-};
-static GROM_CONFIG(grom7_config)
+ if (m_pcb != nullptr) m_pcb->gclock_in(state);
+}
+
+void ti99_cartridge_device::device_config_complete()
{
- false, 7, CARTGROM_TAG, 0x8000, 0x1800, GROMFREQ
-};
+ update_names();
+ m_softlist = false;
+ m_connector = static_cast<ti99_cartridge_connector_device*>(owner());
+}
/*
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)
-{
-}
-
-UINT16 ti99_cartridge_pcb::grom_base()
+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)
{
- 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
diff --git a/src/devices/bus/ti99x/gromport.h b/src/devices/bus/ti99x/gromport.h
index 36900c40045..8f49a7f98d4 100644
--- a/src/devices/bus/ti99x/gromport.h
+++ b/src/devices/bus/ti99x/gromport.h
@@ -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;
};
diff --git a/src/devices/bus/ti99x/ti99defs.h b/src/devices/bus/ti99x/ti99defs.h
index 130c0cfbc40..8d137e6599f 100644
--- a/src/devices/bus/ti99x/ti99defs.h
+++ b/src/devices/bus/ti99x/ti99defs.h
@@ -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"
diff --git a/src/devices/bus/ti99x/videowrp.cpp b/src/devices/bus/ti99x/videowrp.cpp
index 6f09da722e7..387872bba5d 100644
--- a/src/devices/bus/ti99x/videowrp.cpp
+++ b/src/devices/bus/ti99x/videowrp.cpp
@@ -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));
}
/**************************************************************************/
diff --git a/src/devices/bus/ti99x/videowrp.h b/src/devices/bus/ti99x/videowrp.h
index cb339e9dd60..c59069db13b 100644
--- a/src/devices/bus/ti99x/videowrp.h
+++ b/src/devices/bus/ti99x/videowrp.h
@@ -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 )
diff --git a/src/mame/drivers/ti99_4p.cpp b/src/mame/drivers/ti99_4p.cpp
index 0f48e57772b..7da4302262b 100644
--- a/src/mame/drivers/ti99_4p.cpp
+++ b/src/mame/drivers/ti99_4p.cpp
@@ -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);
diff --git a/src/mame/drivers/ti99_4x.cpp b/src/mame/drivers/ti99_4x.cpp
index b8fcb75b3cb..107f3a466e8 100644
--- a/src/mame/drivers/ti99_4x.cpp
+++ b/src/mame/drivers/ti99_4x.cpp
@@ -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*/
diff --git a/src/mame/drivers/ti99_8.cpp b/src/mame/drivers/ti99_8.cpp
index 5e3acc85ff6..9b661f71e82 100644
--- a/src/mame/drivers/ti99_8.cpp
+++ b/src/mame/drivers/ti99_8.cpp
@@ -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 )
{
@@ -661,33 +551,6 @@ WRITE_LINE_MEMBER( ti99_8_state::keyC3 )
}
/*
- 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)
*/
WRITE_LINE_MEMBER( ti99_8_state::cassette_motor )
@@ -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.
+ Enqueue a RESET signal.
*/
-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 )
+WRITE_LINE_MEMBER( ti99_8_state::console_reset )
{
- console_ready_join(READY_SOUND, state);
-}
+ if (TRACE_RESET) logerror("Incoming RESET line = %d\n", state);
+ if (machine().phase() != MACHINE_PHASE_INIT)
+ {
+ // RESET the 9901
+ m_tms9901->rst1_line(state);
-WRITE_LINE_MEMBER( ti99_8_state::console_ready_cart )
-{
- console_ready_join(READY_CART, 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
-WRITE_LINE_MEMBER( ti99_8_state::console_ready_speech )
-{
- console_ready_join(READY_SPEECH, state);
+ // Setting ready to false so that automatic wait states are enabled
+ m_cpu->ready_line(CLEAR_LINE);
+ m_cpu->reset_line(ASSERT_LINE);
+ }
}
/*
- The RESET line leading to a reset of the CPU.
+ The HOLD line leading to the CPU entering the HOLD state.
*/
-WRITE_LINE_MEMBER( ti99_8_state::console_reset )
+WRITE_LINE_MEMBER( ti99_8_state::cpu_hold )
{
- if (machine().phase() != MACHINE_PHASE_INIT)
- {
- m_cpu->set_input_line(INT_9995_RESET, state);
- m_video->reset_vdp(state);
- }
+ 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[] =
-{
- // 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 )
+WRITE_LINE_MEMBER( ti99_8_state::dbin_line )
{
- 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) )
-
- /* Sound hardware */
- MCFG_TI_SOUND_76496_ADD( TISOUND_TAG )
- MCFG_TI_SOUND_READY_HANDLER( WRITELINE(ti99_8_state, console_ready_sound) )
-
- /* Cassette drives */
+ MCFG_PERIBOX_READY_HANDLER( DEVWRITELINE(MAINBOARD8_TAG, mainboard8_device, pbox_ready) )
+
+ // 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))
+
+ // 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))
-
- /* Pascal GROM libraries. */
- MCFG_GROM_LIBRARY_ADD8(pascal1_grom, pascal1)
- MCFG_GROM_LIBRARY_ADD8(pascal2_grom, pascal2)
- MCFG_GROM_LIBRARY_ADD3(pascal3_grom, pascal3)
-
- /* Devices */
- MCFG_DEVICE_ADD(SPEECH_TAG, SPEECH8, 0)
- MCFG_SPEECH8_READY_CALLBACK(WRITELINE(ti99_8_state, console_ready_speech))
+ // 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))
+
+ 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))
+
+ 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