(MESS) Using the split addressing (setaddress ... read/write)

This commit is contained in:
Michael Zapf 2013-09-30 23:16:14 +00:00
parent cda0ac67fb
commit 419b6f0158
14 changed files with 989 additions and 632 deletions

View File

@ -240,6 +240,8 @@ public:
DECLARE_WRITE_LINE_MEMBER(video_wait_states);
DECLARE_WRITE_LINE_MEMBER(clock_out);
DECLARE_WRITE_LINE_MEMBER(dbin_line);
DECLARE_WRITE8_MEMBER(external_operation);
DECLARE_WRITE8_MEMBER(tms9901_interrupt);
@ -284,7 +286,7 @@ private:
*/
static ADDRESS_MAP_START(memmap, AS_PROGRAM, 8, geneve_state)
AM_RANGE(0x0000, 0xffff) AM_DEVREADWRITE(GMAPPER_TAG, geneve_mapper_device, readm, writem)
AM_RANGE(0x0000, 0xffff) AM_DEVREADWRITE(GMAPPER_TAG, geneve_mapper_device, readm, writem) AM_DEVSETOFFSET(GMAPPER_TAG, geneve_mapper_device, setoffset)
ADDRESS_MAP_END
/*
@ -604,7 +606,7 @@ WRITE_LINE_MEMBER( geneve_state::intb )
WRITE_LINE_MEMBER( geneve_state::ext_ready )
{
if (VERBOSE>6) LOG("ti99_8: READY level (ext) =%02x\n", state);
if (VERBOSE>6) LOG("geneve: READY level (ext) = %02x\n", state);
m_ready_line = state;
m_cpu->set_ready((m_ready_line == ASSERT_LINE && m_ready_line1 == ASSERT_LINE)? ASSERT_LINE : CLEAR_LINE);
}
@ -670,13 +672,21 @@ WRITE_LINE_MEMBER( geneve_state::clock_out )
m_mapper->clock_in(state);
}
/*
DBIN line from the CPU. Used to control wait state generation.
*/
WRITE_LINE_MEMBER( geneve_state::dbin_line )
{
m_mapper->dbin(state);
}
static TMS9995_CONFIG( geneve_processor_config )
{
DEVCB_DRIVER_MEMBER(geneve_state, external_operation),
DEVCB_NULL, // Instruction acquisition
DEVCB_DRIVER_LINE_MEMBER(geneve_state, clock_out),
DEVCB_NULL, // wait
DEVCB_NULL, // HOLDA
DEVCB_DRIVER_LINE_MEMBER(geneve_state, dbin_line), // DBIN
INTERNAL_RAM, // use internal RAM
NO_OVERFLOW_INT // The generally available versions of TMS9995 have a deactivated overflow interrupt
};

View File

@ -89,6 +89,7 @@ public:
DECLARE_READ8_MEMBER( interrupt_level );
DECLARE_READ_LINE_MEMBER( ready_connect );
DECLARE_WRITE_LINE_MEMBER( clock_out );
DECLARE_WRITE_LINE_MEMBER( dbin_line );
DECLARE_INPUT_CHANGED_MEMBER( load_interrupt );
TIMER_DEVICE_CALLBACK_MEMBER(ti99_4ev_hblank_interrupt);
@ -601,6 +602,14 @@ WRITE_LINE_MEMBER( ti99_4x_state::clock_out )
m_datamux->clock_in(state);
}
/*
Data bus in (DBIN) line from the CPU.
*/
WRITE_LINE_MEMBER( ti99_4x_state::dbin_line )
{
m_datamux->dbin_in(state);
}
/*****************************************************************************/
/*
@ -822,7 +831,8 @@ static TMS99xx_CONFIG( ti99_cpuconf )
DEVCB_NULL, // Instruction acquisition
DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, clock_out),
DEVCB_NULL, // wait
DEVCB_NULL // Hold acknowledge
DEVCB_NULL, // Hold acknowledge
DEVCB_DRIVER_LINE_MEMBER(ti99_4x_state, dbin_line) // data bus in
};
static JOYPORT_CONFIG( joyport4_60 )

View File

@ -215,7 +215,7 @@ Known Issues (MZ, 2010-11-07)
#include "machine/ti99/gromport.h"
#include "machine/ti99/joyport.h"
#define VERBOSE 0
#define VERBOSE 1
#define LOG logerror
class ti99_8_state : public driver_device
@ -630,6 +630,14 @@ WRITE_LINE_MEMBER( ti99_8_state::keyC3 )
WRITE_LINE_MEMBER( ti99_8_state::CRUS )
{
m_mapper->CRUS_set(state==ASSERT_LINE);
if (state==ASSERT_LINE)
{
m_gromport->set_grom_base(0x9800, 0xfbf1);
}
else
{
m_gromport->set_grom_base(0xf830, 0xfff1);
}
}
/*
@ -795,8 +803,8 @@ static TMS9995_CONFIG( ti99_8_processor_config )
DEVCB_DRIVER_MEMBER(ti99_8_state, external_operation),
DEVCB_NULL, // Instruction acquisition
DEVCB_DRIVER_LINE_MEMBER(ti99_8_state, clock_out),
DEVCB_NULL, // wait
DEVCB_NULL, // HOLDA
DEVCB_NULL, // DBIN
NO_INTERNAL_RAM,
NO_OVERFLOW_INT
};
@ -962,6 +970,7 @@ void ti99_8_state::machine_reset()
// But we assert the line here so that the system starts running
m_ready_line = m_ready_line1 = ASSERT_LINE;
m_gromport->set_grom_base(0x9800, 0xfff1);
}
static MACHINE_CONFIG_START( ti99_8_60hz, ti99_8_state )

View File

@ -824,7 +824,8 @@ static TMS99xx_CONFIG( cpuconf )
DEVCB_NULL, // Instruction acquisition
DEVCB_NULL, // Clock out
DEVCB_NULL, // wait
DEVCB_NULL // Hold acknowledge
DEVCB_NULL, // Hold acknowledge
DEVCB_NULL // DBIN
};
static MACHINE_CONFIG_START( tm990_189, tm990189_state )

View File

@ -120,54 +120,48 @@ void ti99_datamux_device::write_all(address_space& space, UINT16 addr, UINT8 val
}
}
void ti99_datamux_device::setaddress_all(address_space& space, UINT16 addr)
{
attached_device *dev = m_devices.first();
while (dev != NULL)
{
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;
}
}
/*
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)
TODO: Check two-pass operation
*/
READ16_MEMBER( ti99_datamux_device::read )
{
UINT8 hbyte = 0;
UINT16 addr = (offset << 1);
// 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_use32k)
if (m_base32k != 0)
{
UINT16 base = 0;
if ((addr & 0xe000)==0x2000) base = 0x1000;
if (((addr & 0xe000)==0xa000) || ((addr & 0xc000)==0xc000)) base = 0x4000;
if (base != 0)
{
UINT16 reply = m_ram16b[offset-base];
return reply & mem_mask;
}
UINT16 reply = m_ram16b[offset-m_base32k];
return reply & mem_mask;
}
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 (VERBOSE>3) LOG("datamux: read even byte from address %04x -> %02x\n", m_addr_buf, hbyte);
// Read the odd address into the latch
read_all(space, addr+1, &m_latch);
// Reading the even address now (addr)
read_all(space, addr, &hbyte);
// Insert four wait states and let CPU enter wait state
// The counter in the real console is implemented by a shift register
// that is triggered on a memory access
// We cannot split the wait states between the read accesses before we
// have a split-phase read access in the core
m_waitcount = 6;
m_ready(CLEAR_LINE);
// use the latch and the currently read byte and put it on the 16bit bus
return ((hbyte<<8) | m_latch) & mem_mask;
return ((hbyte<<8) | m_latch) & mem_mask;
}
}
/*
@ -175,57 +169,117 @@ READ16_MEMBER( ti99_datamux_device::read )
*/
WRITE16_MEMBER( ti99_datamux_device::write )
{
UINT16 addr = (offset << 1);
// Although MESS allows for using mem_mask to address parts of the
// data bus, this is not used in the TMS implementation. In fact, all
// accesses are true 16-bit accesses. We check for mem_mask always
// being ffff.
// printf("write addr=%04x, value=%04x\n", addr, data);
// Handle the internal 32K expansion
if (m_use32k)
if (m_base32k != 0)
{
UINT16 base = 0;
if ((addr & 0xe000)==0x2000) base = 0x1000;
if (((addr & 0xe000)==0xa000) || ((addr & 0xc000)==0xc000)) base = 0x4000;
if (base != 0)
{
m_ram16b[offset-base] = data;
return;
}
m_ram16b[offset-m_base32k] = data;
}
else
{
// Otherwise the datamux is in normal operation which means it puts
// the even value into the latch and outputs the odd value now.
m_latch = (data >> 8) & 0xff;
// write odd byte
write_all(space, addr+1, data & 0xff);
// write even byte
write_all(space, addr, (data>>8) & 0xff);
// Insert four wait states and let CPU enter wait state
m_waitcount = 6;
m_ready(CLEAR_LINE);
// write odd byte
if (VERBOSE>3) LOG("datamux: write odd byte to address %04x <- %02x\n", m_addr_buf+1, data & 0xff);
write_all(space, m_addr_buf+1, data & 0xff);
}
}
/*
Called when the memory access starts by setting the address bus. From that
point on, we suspend the CPU until all operations are done.
*/
SETOFFSET_MEMBER( ti99_datamux_device::setoffset )
{
if (VERBOSE>6) LOG("set address %04x\n", offset << 1);
if (VERBOSE>6) LOG("datamux: set address %04x\n", offset << 1);
// 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;
}
// Suspend the CPU if not using the 32K
if (m_base32k == 0)
{
// propagate the setaddress operation
// First the odd address
setaddress_all(space, m_addr_buf+1);
m_ready(CLEAR_LINE);
}
else m_waitcount = 0;
}
/*
The datamux is connected to the clock line in order to operate
the wait state counter.
the wait state counter and to read/write the bytes.
*/
void ti99_datamux_device::clock_in(int clock)
{
if (clock==ASSERT_LINE && m_waitcount!=0)
// return immediately if the datamux is currently inactive
if (m_waitcount>0)
{
m_waitcount--;
if (m_waitcount==0) m_ready(ASSERT_LINE);
if (VERBOSE>6) LOG("datamux: wait count %d\n", m_waitcount);
if (m_read_mode)
{
// Reading
if (clock==ASSERT_LINE)
{ // raising edge
m_waitcount--;
if (m_waitcount==0) m_ready(ASSERT_LINE);
if (m_waitcount==2)
{
// read odd byte
read_all(*m_spacep, m_addr_buf+1, &m_latch);
if (VERBOSE>3) LOG("datamux: read odd byte from address %04x -> %02x\n", m_addr_buf+1, m_latch);
// do the setaddress for the even address
setaddress_all(*m_spacep, m_addr_buf);
}
}
}
else
{
if (clock==ASSERT_LINE)
{ // raising edge
m_waitcount--;
if (m_waitcount==0) m_ready(ASSERT_LINE);
}
else
{ // falling edge
if (m_waitcount==2)
{
// do the setaddress for the even address
setaddress_all(*m_spacep, m_addr_buf);
// write even byte
if (VERBOSE>3) LOG("datamux: write even byte to address %04x <- %02x\n", m_addr_buf, m_latch);
write_all(*m_spacep, m_addr_buf, m_latch);
}
}
}
}
}
void ti99_datamux_device::dbin_in(int state)
{
m_read_mode = (state==ASSERT_LINE);
if (VERBOSE>6) LOG("datamux: data bus in = %d\n", m_read_mode? 1:0 );
}
/***************************************************************************
DEVICE LIFECYCLE FUNCTIONS
***************************************************************************/
@ -308,6 +362,8 @@ void ti99_datamux_device::device_reset(void)
m_waitcount = 0;
m_latch = 0;
m_read_mode = true;
}
INPUT_PORTS_START( datamux )

View File

@ -73,6 +73,7 @@ public:
DECLARE_SETOFFSET_MEMBER( setoffset );
void clock_in(int state);
void dbin_in(int state);
protected:
/* Constructor */
@ -82,15 +83,27 @@ protected:
virtual ioport_constructor device_input_ports() const;
private:
// Keeps the address space pointer
address_space* m_spacep;
// Common read routine
void read_all(address_space& space, UINT16 addr, UINT8 *target);
// Common write routine
void write_all(address_space& space, UINT16 addr, UINT8 value);
// Common set address method
void setaddress_all(address_space& space, UINT16 addr);
// Ready line to the CPU
devcb_resolved_write_line m_ready;
/* 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;
@ -106,6 +119,9 @@ private:
/* 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;
};

File diff suppressed because it is too large Load Diff

View File

@ -135,10 +135,12 @@ public:
DECLARE_READ8_MEMBER( readm );
DECLARE_WRITE8_MEMBER( writem );
DECLARE_SETOFFSET_MEMBER( setoffset );
DECLARE_INPUT_CHANGED_MEMBER( gm_changed );
void clock_in(int state);
void dbin(int state);
protected:
virtual void device_start();
@ -157,6 +159,8 @@ private:
bool m_video_waitstates;
bool m_extra_waitstates;
bool m_read_mode;
// Mapper function
bool m_geneve_mode;
bool m_direct_mode;
@ -166,6 +170,11 @@ private:
bool m_cartridge7_writable;
int m_map[8];
int m_mapdecode;
int m_offset;
int m_physaddr;
// Genmod modifications
bool m_turbo;
bool m_genmod;

View File

@ -54,6 +54,7 @@ ti998_mapper_device::ti998_mapper_device(const machine_config &mconfig, const ch
CRU access
***************************************************************************/
#define HEXBUS_CRU_BASE 0x1700
#define MAPPER_CRU_BASE 0x2700
void ti998_mapper_device::crureadz(offs_t offset, UINT8 *value)
@ -83,6 +84,19 @@ void ti998_mapper_device::cruwrite(offs_t offset, UINT8 data)
machine().schedule_soft_reset();
break;
}
return;
}
if ((offset & 0xff00)==HEXBUS_CRU_BASE)
{
if (VERBOSE>5) LOG("mapper8: Set CRU>%04x (Hexbus) to %d\n",offset,data);
return;
}
if ((offset & 0xff00)>=0x0100)
{
if (VERBOSE>5) LOG("mapper8: Set CRU>%04x (unknown) to %d\n",offset,data);
return;
}
}
@ -234,6 +248,7 @@ void ti998_mapper_device::mapwrite(int offset, UINT8 data)
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 (VERBOSE>7) LOG("mapper8: load %d=%08x\n", i, m_pas_offset[i]);
}
}
else
@ -247,6 +262,7 @@ void ti998_mapper_device::mapwrite(int offset, UINT8 data)
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 (VERBOSE>7) LOG("mapper8: save %d=%08x\n", i, m_pas_offset[i]);
}
}
}

View File

@ -249,6 +249,14 @@ WRITE8_MEMBER(peribox_device::write)
}
}
SETADDRESS_DBIN_MEMBER(peribox_device::setaddress_dbin)
{
for (int i=2; i <= 8; i++)
{
if (m_slot[i]!=NULL) m_slot[i]->setaddress_dbin(space, offset | m_address_prefix, state);
}
}
void peribox_device::crureadz(offs_t offset, UINT8 *value)
{
for (int i=2; i <= 8; i++)
@ -579,6 +587,11 @@ WRITE8_MEMBER(peribox_slot_device::write)
m_card->write(space, offset, data, mem_mask);
}
SETADDRESS_DBIN_MEMBER(peribox_slot_device::setaddress_dbin)
{
m_card->setaddress_dbin(space, offset, state);
}
void peribox_slot_device::crureadz(offs_t offset, UINT8 *value)
{
m_card->crureadz(offset, value);

View File

@ -49,9 +49,11 @@ public:
peribox_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
peribox_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);
// Next six methods are called from the console
// Next seven methods are called from the console
DECLARE_READ8Z_MEMBER(readz);
DECLARE_WRITE8_MEMBER(write);
DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin);
void crureadz(offs_t offset, UINT8 *value);
void cruwrite(offs_t offset, UINT8 value);
DECLARE_WRITE_LINE_MEMBER(senila);
@ -143,6 +145,8 @@ public:
// Called from the box (direction to card)
DECLARE_READ8Z_MEMBER(readz);
DECLARE_WRITE8_MEMBER(write);
DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin);
DECLARE_WRITE_LINE_MEMBER(senila);
DECLARE_WRITE_LINE_MEMBER(senilb);

View File

@ -28,8 +28,6 @@
#define VERBOSE 1
#define LOG logerror
#define REAL_TIMING 0
/****************************************************************************/
ti_speech_synthesizer_device::ti_speech_synthesizer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
@ -37,79 +35,23 @@ ti_speech_synthesizer_device::ti_speech_synthesizer_device(const machine_config
{
}
/*
Comments on real timing in the TMS5200 emulation
Real timing means that the synthesizer clears the /READY line (puts high)
whenever a read or write access is in progress. This is done by setting
/RS and /WS lines, according to the read or write operation. The /READY line
is asserted again after some time. Real timing is used once the tms5220_wsq_w
and tms5220_rsq_w are called.
Within the TI systems, the /RS and /WS lines are controlled directly by the
address bus. There is currently no way to insert wait states between
the address setting and the data bus sampling, since this is an atomic
operation in the emulator (read_byte). It would be necessary to somehow
announce the pending read before it actually happens so that devices
like this VSP may insert wait states before the read.
The TMS5220 implementation assumes that wait states are respected and
therefore delivers bad values when queried too early. It uses a latch that
gets the new value after some time has expired.
To fix this we have to modify the RS/WS methods in TMS5200 to immediately
set the status (after updating the sound status, or the status will be
outdated too early).
Also note that the /RS and /WS lines must be cleared (put to high) when the
read is done. Again, this is not possible with the current implementation.
So we do this in the ready callback.
On the bottom line we will stay with the not-REAL_TIMING for now and wait
for the core to allow for split read accesses.
*/
/*
Memory read
*/
#if REAL_TIMING
// ====== This is the version with real timing =======
READ8Z_MEMBER( ti_speech_synthesizer_device::readz )
{
if ((offset & m_select_mask)==m_select_value)
{
m_vsp->wsq_w(TRUE);
m_vsp->rsq_w(FALSE);
*value = m_vsp->read(offset) & 0xff;
if (VERBOSE>4) LOG("spchsyn: read value = %02x\n", *value);
}
}
/*
Memory write
*/
WRITE8_MEMBER( ti_speech_synthesizer_device::write )
{
if ((offset & m_select_mask)==(m_select_value | 0x0400))
{
m_vsp->rsq_w(m_vsp, TRUE);
m_vsp->wsq_w(m_vsp, FALSE);
if (VERBOSE>4) LOG("spchsyn: write value = %02x\n", data);
m_vsp->write(offset, data);
}
}
#else
// ====== This is the version without real timing =======
READ8Z_MEMBER( ti_speech_synthesizer_device::readz )
{
if ((offset & m_select_mask)==m_select_value)
{
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 (VERBOSE>4) LOG("spchsyn: read value = %02x\n", *value);
// We should clear the lines at this point. The TI-99/4A clears the
// lines by setting the address bus to a different value, but the
// Geneve may behave differently. This may not 100% reflect the real
// situation, but it ensures a safe processing.
m_vsp->rsq_w(TRUE);
m_vsp->wsq_w(TRUE);
}
}
@ -120,26 +62,51 @@ WRITE8_MEMBER( ti_speech_synthesizer_device::write )
{
if ((offset & m_select_mask)==(m_select_value | 0x0400))
{
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 (VERBOSE>8) LOG("spchsyn: time to ready: %f -> %d\n", 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 (VERBOSE>4) LOG("spchsyn: write value = %02x\n", data);
m_vsp->data_w(space, offset, data);
// Note that we must NOT clear the lines here. Find the lines in the
// READY callback below.
}
}
SETADDRESS_DBIN_MEMBER( ti_speech_synthesizer_device::setaddress_dbin )
{
if ((offset & m_select_mask & ~0x0400)==m_select_value)
{
if (VERBOSE>4) LOG("spchsyn: set address = %04x, dbin = %d\n", offset, state);
m_read_mode = (state==ASSERT_LINE);
bool readop = (offset & 0x0400)==0;
if (m_read_mode != readop)
{
// reset all; this is not a valid access
m_vsp->rsq_w(TRUE);
m_vsp->wsq_w(TRUE);
}
else
{
if (readop)
{
// Caution: We MUST first clear (TRUE) one line to avoid
// both RS* and WS* be asserted (otherwise tms5220 will report "illegal")
m_vsp->wsq_w(TRUE);
m_vsp->rsq_w(FALSE);
}
else
{
m_vsp->rsq_w(TRUE);
m_vsp->wsq_w(FALSE);
}
}
}
else
{
// If other address, turn off RS* and WS* (negative logic!)
m_vsp->rsq_w(TRUE);
m_vsp->wsq_w(TRUE);
return;
}
}
#endif
/****************************************************************************/
@ -151,14 +118,12 @@ WRITE_LINE_MEMBER( ti_speech_synthesizer_device::speech_ready )
m_slot->set_ready((state==0)? ASSERT_LINE : CLEAR_LINE);
if (VERBOSE>5) LOG("spchsyn: READY = %d\n", (state==0));
#if REAL_TIMING
// Need to do that here (see explanations above)
if (state==0)
if ((state==0) && !m_read_mode)
{
// Clear the lines only when we are done with writing.
m_vsp->rsq_w(TRUE);
m_vsp->wsq_w(TRUE);
}
#endif
}
void ti_speech_synthesizer_device::device_start()
@ -172,6 +137,7 @@ void ti_speech_synthesizer_device::device_config_complete()
void ti_speech_synthesizer_device::device_reset()
{
if (VERBOSE>5) LOG("spchsyn: reset\n");
if (m_genmod)
{
m_select_mask = 0x1ffc01;
@ -182,6 +148,7 @@ void ti_speech_synthesizer_device::device_reset()
m_select_mask = 0x7fc01;
m_select_value = 0x79000;
}
m_read_mode = false;
}
MACHINE_CONFIG_FRAGMENT( ti99_speech )

View File

@ -23,6 +23,7 @@ public:
ti_speech_synthesizer_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
DECLARE_READ8Z_MEMBER(readz);
DECLARE_WRITE8_MEMBER(write);
DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin);
void crureadz(offs_t offset, UINT8 *value) { };
void cruwrite(offs_t offset, UINT8 value) { };
@ -42,6 +43,7 @@ protected:
private:
cd2501e_device *m_vsp;
bool m_read_mode;
};
#endif

View File

@ -49,6 +49,15 @@
#define READ8Z_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT8 *value, ATTR_UNUSED UINT8 mem_mask)
#define DECLARE_READ8Z_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED UINT8 *value, ATTR_UNUSED UINT8 mem_mask = 0xff)
/*
For almost all applications of setoffset, we also need the data bus
direction. This line is called DBIN on the TI CPUs, but as we do not assume
that this is a general rule, we use new macros here which contain the
DBIN setting.
*/
#define SETADDRESS_DBIN_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED int state)
#define DECLARE_SETADDRESS_DBIN_MEMBER(name) void name(ATTR_UNUSED address_space &space, ATTR_UNUSED offs_t offset, ATTR_UNUSED int state)
#define GENMOD 0x01
/*
@ -65,6 +74,7 @@ public:
: device_t(mconfig, type, name, tag, owner, clock, shortname, source) { }
virtual DECLARE_READ8Z_MEMBER(readz) =0;
virtual DECLARE_WRITE8_MEMBER(write) =0;
virtual DECLARE_SETADDRESS_DBIN_MEMBER( setaddress_dbin ) { };
};
class bus16z_device : device_t
@ -72,6 +82,7 @@ class bus16z_device : device_t
public:
virtual DECLARE_READ16Z_MEMBER(read16z) =0;
virtual DECLARE_WRITE16_MEMBER(write16) =0;
virtual DECLARE_SETADDRESS_DBIN_MEMBER( setaddress_dbin ) { };
};
/****************************************************************************