From 419b6f01585bbe99a4264b10dbd1d2be3bfd0c91 Mon Sep 17 00:00:00 2001 From: Michael Zapf Date: Mon, 30 Sep 2013 23:16:14 +0000 Subject: [PATCH] (MESS) Using the split addressing (setaddress ... read/write) --- src/mess/drivers/geneve.c | 16 +- src/mess/drivers/ti99_4x.c | 12 +- src/mess/drivers/ti99_8.c | 13 +- src/mess/drivers/tm990189.c | 3 +- src/mess/machine/ti99/datamux.c | 174 +++-- src/mess/machine/ti99/datamux.h | 16 + src/mess/machine/ti99/genboard.c | 1193 ++++++++++++++++++------------ src/mess/machine/ti99/genboard.h | 9 + src/mess/machine/ti99/mapper8.c | 16 + src/mess/machine/ti99/peribox.c | 13 + src/mess/machine/ti99/peribox.h | 6 +- src/mess/machine/ti99/spchsyn.c | 137 ++-- src/mess/machine/ti99/spchsyn.h | 2 + src/mess/machine/ti99/ti99defs.h | 11 + 14 files changed, 989 insertions(+), 632 deletions(-) diff --git a/src/mess/drivers/geneve.c b/src/mess/drivers/geneve.c index c09e8790da2..5d6e61d4ebd 100644 --- a/src/mess/drivers/geneve.c +++ b/src/mess/drivers/geneve.c @@ -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 }; diff --git a/src/mess/drivers/ti99_4x.c b/src/mess/drivers/ti99_4x.c index fe7d47e5b03..f0dd558779d 100644 --- a/src/mess/drivers/ti99_4x.c +++ b/src/mess/drivers/ti99_4x.c @@ -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 ) diff --git a/src/mess/drivers/ti99_8.c b/src/mess/drivers/ti99_8.c index 96c48084097..45e585ace85 100644 --- a/src/mess/drivers/ti99_8.c +++ b/src/mess/drivers/ti99_8.c @@ -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 ) diff --git a/src/mess/drivers/tm990189.c b/src/mess/drivers/tm990189.c index a52dbef10d7..29840800d53 100644 --- a/src/mess/drivers/tm990189.c +++ b/src/mess/drivers/tm990189.c @@ -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 ) diff --git a/src/mess/machine/ti99/datamux.c b/src/mess/machine/ti99/datamux.c index 4963ff32331..76989a0d609 100644 --- a/src/mess/machine/ti99/datamux.c +++ b/src/mess/machine/ti99/datamux.c @@ -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(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 ) diff --git a/src/mess/machine/ti99/datamux.h b/src/mess/machine/ti99/datamux.h index 441f2e7a3f8..0b9c9c85a27 100644 --- a/src/mess/machine/ti99/datamux.h +++ b/src/mess/machine/ti99/datamux.h @@ -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 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; }; diff --git a/src/mess/machine/ti99/genboard.c b/src/mess/machine/ti99/genboard.c index 6d062f07fed..d804910e472 100644 --- a/src/mess/machine/ti99/genboard.c +++ b/src/mess/machine/ti99/genboard.c @@ -264,13 +264,13 @@ TI mode: void geneve_mapper_device::do_wait(int min) { - min = min + 1; +// min = min + 1; // Extra waitstates? if (m_extra_waitstates && min < 4) min = 3; m_waitcount = min; if (m_waitcount > 0) { - if (VERBOSE>8) LOG("genboard: Pulling down READY line for %d cycles\n", m_waitcount); + if (VERBOSE>7) LOG("genboard: Pulling down READY line for %d cycles\n", m_waitcount); m_ready(CLEAR_LINE); } } @@ -278,533 +278,755 @@ void geneve_mapper_device::do_wait(int min) /************************************************************************ Called by the address map ************************************************************************/ +/* + Constants for mapper decoding. Naming scheme: + M=mapper + L=Logical space; P=Physical space + G=Geneve mode; T=TI mode +*/ +enum +{ + MLGVIDEO=1, + MLGMAPPER, + MLGKEY, + MLGCLOCK, + MLGSOUND, + MLTMAPPER, + MLTKEY, + MLTCLOCK, + MLTVIDEO, + MLTSPEECH, + MLTGROM, + MLTSOUND, + MPGDRAM, + MPGEXP, + MPGEPROM, + MPGSRAM, + MPGBOX, + MPGMDRAM, + MPGMEPROM, + MPGMBOX +}; +/* + Read a byte via the data bus. The decoding has already been done in the + SETOFFSET method, and we re-use the values stored there to quickly + access the appropriate component. +*/ READ8_MEMBER( geneve_mapper_device::readm ) { UINT8 value = 0; - int page; - UINT32 physaddr; // Premature access. The CPU reads the start vector before RESET. if (m_eprom==NULL) return 0; - if (m_geneve_mode) + switch (m_mapdecode) { - // TODO: shortcut offset & 0xffc0 = 0xf100 - if ((offset & 0xfff5)==0xf100) + case MLGVIDEO: + m_video->readz(space, m_offset, &value, mem_mask); + if (VERBOSE>7) LOG("genboard: Read video %04x -> %02x\n", m_offset, value); + break; + + case MLGMAPPER: + // mapper + value = m_map[m_offset]; + if (VERBOSE>7) LOG("genboard: read mapper %04x -> %02x\n", m_offset, value); + break; + + case MLGKEY: + // key + value = m_keyboard->get_recent_key(); + if (VERBOSE>7) LOG("genboard: Read keyboard -> %02x\n", value); + break; + + case MLGCLOCK: + // clock + // tests on the real machine showed that + // upper nibble is 0xf (probably because of the location at 0xf130?) + value = m_clock->read(space, m_offset) | 0xf0; + if (VERBOSE>7) LOG("genboard: Read clock %04x -> %02x\n", m_offset, value); + break; + + case MLTMAPPER: + // mapper + value = m_map[m_offset]; + if (VERBOSE>7) LOG("genboard: Read mapper %04x -> %02x\n", m_offset, value); + break; + + case MLTKEY: + // key + value = m_keyboard->get_recent_key(); + if (VERBOSE>7) LOG("genboard: Read keyboard -> %02x\n", value); + break; + + case MLTCLOCK: + // clock + // upper nibble is 1, only last byte gets a 2 + // probably because of the location at 8010...8020? + // (TI mode used swapped byte order) + // unless we use a workspace at >F000, in which case we get 8x values + // Obscure, needs more investigation. We might as well ignore this, + // as the high nibble is obviously undefined and takes some past + // value floating around. + value = m_clock->read(space, m_offset); + value |= (m_offset==0x000f)? 0x20 : 0x10; + if (VERBOSE>7) LOG("genboard: Read clock %04x -> %02x\n", m_offset, value); + break; + + case MLTVIDEO: + // video + // ++++ ++-- ---- ---+ + // 1000 1000 0000 00x0 + m_video->readz(space, m_offset, &value, mem_mask); + if (VERBOSE>7) LOG("genboard: Read video %04x -> %02x\n", m_offset, value); + break; + + case MLTSPEECH: + // speech + // ++++ ++-- ---- ---+ + // 1001 0000 0000 0000 + // We need to add the address prefix bits + m_peribox->readz(space, m_offset, &value, mem_mask); + if (VERBOSE>7) LOG("genboard: Read speech -> %02x\n", value); + break; + + case MLTGROM: + // grom simulation + // ++++ ++-- ---- ---+ + // 1001 1000 0000 00x0 + value = read_grom(space, m_offset, mem_mask); + if (VERBOSE>7) LOG("genboard: Read GROM %04x -> %02x\n", m_offset, value); + break; + + case MLGSOUND: + case MLTSOUND: + value = 0; + break; + + + case MPGDRAM: + // DRAM. + value = m_dram[m_physaddr]; +// printf("dram read physaddr = %06x logaddr = %04x value = %02x\n", m_physaddr, m_offset, value); + if (VERBOSE>7) LOG("genboard: Read DRAM %04x (%06x) -> %02x\n", m_offset, m_physaddr, value); + break; + + case MPGEXP: + // On-board memory expansion for standard Geneve (never used) + if (VERBOSE>7) LOG("genboard: Read unmapped area %06x\n", m_physaddr); + value = 0; + break; + + case MPGEPROM: + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... + value = m_eprom[m_physaddr]; + if (VERBOSE>7) LOG("genboard: Read EPROM %04x (%06x) -> %02x\n", m_offset, m_physaddr, value); + break; + + case MPGSRAM: + if ((m_physaddr & m_sram_mask)==m_sram_val) { - // video - // ++++ ++++ ++++ -+-+ - // 1111 0001 0000 0000 - // 1111 0001 0000 0010 - // 1111 0001 0000 1000 - // 1111 0001 0000 1010 - - // 1 WS is always added; any pending video wait states are canceled - m_video_waiting = false; - do_wait(1); - - // Initialize wait state timer - // Create 16 wait states (2 more than expected, experimenting) - if (m_video_waitstates) - do_wait(16); - - m_video->readz(space, offset, &value, mem_mask); - if (VERBOSE>7) LOG("genboard: Read video %04x -> %02x\n", offset, value); - return value; - } - if ((offset & 0xfff8)==0xf110) - { - // mapper - value = m_map[offset & 0x0007]; - - // Add appropriate number of waitstates - // 1 WS is added at least - do_wait(1); - if (VERBOSE>7) LOG("genboard: read mapper %04x -> %02x\n", offset, value); - return value; - } - if ((offset & 0xfff8) == 0xf118) - { - // key - value = m_keyboard->get_recent_key(); - do_wait(1); - if (VERBOSE>7) LOG("genboard: Read keyboard -> %02x\n", value); - return value; - } - if ((offset & 0xfff0)==0xf130) - { - // clock - // tests on the real machine showed that - // upper nibble is 0xf (probably because of the location at 0xf130?) - value = m_clock->read(space, offset & 0x000f) | 0xf0; - do_wait(1); - if (VERBOSE>7) LOG("genboard: Read clock %04x -> %02x\n", offset, value); - return value; - } - } - else // TI mode - { - if ((offset & 0xfff8)==0x8000) - { - // mapper - value = m_map[offset & 0x0007]; - do_wait(1); - if (VERBOSE>7) LOG("genboard: Read mapper %04x -> %02x\n", offset, value); - return value; - } - if ((offset & 0xfff8)== 0x8008) - { - // key - value = m_keyboard->get_recent_key(); - do_wait(1); - if (VERBOSE>7) LOG("genboard: Read keyboard -> %02x\n", value); - return value; - } - if ((offset & 0xfff0)==0x8010) - { - // clock - // upper nibble is 1, only last byte gets a 2 - // probably because of the location at 8010...8020? - // (TI mode used swapped byte order) - // unless we use a workspace at >F000, in which case we get 8x values - // Obscure, needs more investigation. We might as well ignore this, - // as the high nibble is obviously undefined and takes some past - // value floating around. - value = m_clock->read(space, offset & 0x000f); - value |= ((offset & 0x000f)==0x000f)? 0x20 : 0x10; - - do_wait(1); - if (VERBOSE>7) LOG("genboard: Read clock %04x -> %02x\n", offset, value); - return value; - } - if ((offset & 0xfc01)==0x8800) - { - // video - // ++++ ++-- ---- ---+ - // 1000 1000 0000 00x0 - - // 1 WS is always added; any pending video waitstates are canceled - m_video_waiting = false; - do_wait(1); - - // Initialize waitstate timer - // Create 14 waitstates (+2, see above) - if (m_video_waitstates) - do_wait(16); - - m_video->readz(space, offset, &value, mem_mask); - if (VERBOSE>7) LOG("genboard: Read video %04x -> %02x\n", offset, value); - return value; - } - if ((offset & 0xfc01)==0x9000) - { - // speech - // ++++ ++-- ---- ---+ - // 1001 0000 0000 0000 - // We need to add the address prefix bits - m_peribox->readz(space, offset | ((m_genmod)? 0x170000 : 0x070000), &value, mem_mask); - - do_wait(1); - if (VERBOSE>7) LOG("genboard: Read speech -> %02x\n", value); - return value; - } - if ((offset & 0xfc01)==0x9800) - { - // grom simulation - // ++++ ++-- ---- ---+ - // 1001 1000 0000 00x0 - value = read_grom(space, offset, mem_mask); - - do_wait(1); - if (VERBOSE>7) LOG("genboard: Read GROM %04x -> %02x\n", offset, value); - return value; - } - } - - page = (offset & 0xe000) >> 13; - - if (m_direct_mode) - { - physaddr = 0x1e0000; // points to boot eprom - } - else - { - if (!m_geneve_mode && page==3) - { - // Cartridge paging in TI mode - // See also cartridge type "paged" in gromport.h - // value 0x36 = 0 0110 110x xxxx xxxx xxxx (page 1) - // value 0x37 = 0 0110 111x xxxx xxxx xxxx (page 2) - // Only use this if there are 2*8 KiB cartridge ROM - if (VERBOSE>7) LOG("genboard: Cartridge area\n"); - if (m_cartridge_size==0x4000 && m_cartridge_secondpage) physaddr = 0x06e000; - else physaddr = 0x06c000; - } - else - { - physaddr = (m_map[page] << 13); - } - } - - physaddr |= (offset & 0x1fff); - - if (!m_genmod) - { - // Standard Geneve - if ((physaddr & 0x180000)==0x000000) - { - // DRAM. One wait state. - do_wait(1); - - value = m_dram[physaddr & 0x07ffff]; -// printf("dram read physaddr = %06x logaddr = %04x value = %02x\n", physaddr, offset, value); - if (VERBOSE>7) LOG("genboard: Read DRAM %04x (%06x) -> %02x\n", offset, physaddr, value); - return value; - } - - if ((physaddr & 0x180000)==0x080000) - { - // On-board memory expansion for standard Geneve (never used) - do_wait(1); - if (VERBOSE>7) LOG("genboard: Read unmapped area %06x\n", physaddr); - return 0; - } - - if ((physaddr & 0x1e0000)==0x1e0000) - { - // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) - // mirrored for f0, f2, f4, ...; f1, f3, f5, ... - value = m_eprom[physaddr & 0x003fff]; - do_wait(0); - if (VERBOSE>7) LOG("genboard: Read EPROM %04x (%06x) -> %02x\n", offset, physaddr, value); - return value; - } - - if ((physaddr & 0x180000)==0x180000) - { - if ((physaddr & m_sram_mask)==m_sram_val) - { - value = m_sram[physaddr & ~m_sram_mask]; - } - // Return in any case -// printf("sram read physaddr = %06x logaddr = %04x value = %02x\n", physaddr, offset, value); - do_wait(0); - if (VERBOSE>7) LOG("genboard: Read SRAM %04x (%06x) -> %02x\n", offset, physaddr, value); - return value; + value = m_sram[m_physaddr & ~m_sram_mask]; } + else value = 0; + // Return in any case +// printf("sram read physaddr = %06x logaddr = %04x value = %02x\n", m_physaddr, m_offset, value); + if (VERBOSE>7) LOG("genboard: Read SRAM %04x (%06x) -> %02x\n", m_offset, m_physaddr, value); + break; + case MPGBOX: // Route everything else to the P-Box // 0x000000-0x07ffff for the stock Geneve (AMC,AMB,AMA,A0 ...,A15) // 0x000000-0x1fffff for the GenMod.(AME,AMD,AMC,AMB,AMA,A0 ...,A15) - // Add a wait state - do_wait(1); - physaddr = (physaddr & 0x0007ffff); // 19 bit address (with AMA..AMC) - m_peribox->readz(space, physaddr, &value, mem_mask); - if (VERBOSE>7) LOG("genboard: Read P-Box %04x (%06x) -> %02x\n", offset, physaddr, value); - return value; - } - else - { - // GenMod mode - if ((m_timode) && ((physaddr & 0x180000)==0x000000)) - { - // DRAM. One wait state. - value = m_dram[physaddr & 0x07ffff]; - if (!m_turbo) do_wait(1); - return value; - } + m_peribox->readz(space, m_physaddr, &value, mem_mask); + if (VERBOSE>7) LOG("genboard: Read P-Box %04x (%06x) -> %02x\n", m_offset, m_physaddr, value); + break; - if ((physaddr & 0x1e0000)==0x1e0000) - { - // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) - // mirrored for f0, f2, f4, ...; f1, f3, f5, ... - value = m_eprom[physaddr & 0x003fff]; - do_wait(0); - return value; - } + case MPGMDRAM: + // DRAM. One wait state. + value = m_dram[m_physaddr]; + break; + + case MPGMEPROM: + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... + value = m_eprom[m_physaddr]; + break; + + case MPGMBOX: // Route everything else to the P-Box - physaddr = (physaddr & 0x001fffff); // 21 bit address for Genmod - - if (!m_turbo) do_wait(1); - // Check: Are waitstates completely turned off for turbo mode, or - // merely the waitstates for DRAM memory access and box access? - - m_peribox->readz(space, physaddr, &value, mem_mask); - return value; + m_peribox->readz(space, m_physaddr, &value, mem_mask); + break; } + return value; } - -/* -Geneve mode: -f100 / fff1: v9938_w -f110 / fff8: mapper_w -f120 / fff0: sound_w -f130 / fff0: clock_w - -TI mode: -8000 / fff8: mapper_w -8010 / fff0: clock_w -8400 / fc00: sound_w -8c00 / fff9: v9938_w -9400 / fc00: speech_w -9c00 / fffd: grom_w - -*/ - WRITE8_MEMBER( geneve_mapper_device::writem ) { - UINT32 physaddr; + switch (m_mapdecode) + { + case MLGVIDEO: + // video + // ++++ ++++ ++++ ---+ + // 1111 0001 0000 .cc0 + m_video->write(space, m_offset, data, mem_mask); + if (VERBOSE>7) LOG("genboard: Write video %04x <- %02x\n", offset, data); + break; + + case MLGMAPPER: + // mapper + m_map[m_offset] = data; + if (VERBOSE>7) LOG("genboard: Write mapper %04x <- %02x\n", offset, data); + break; + + case MLGCLOCK: + // clock + // ++++ ++++ ++++ ---- + m_clock->write(space, m_offset, data); + if (VERBOSE>7) LOG("genboard: Write clock %04x <- %02x\n", offset, data); + break; + + case MLGSOUND: + // sound + // ++++ ++++ ++++ ---+ + m_sound->write(space, 0, data, mem_mask); + if (VERBOSE>7) LOG("genboard: Write sound <- %02x\n", data); + break; + + case MLTMAPPER: + // mapper + m_map[m_offset] = data; + if (VERBOSE>7) LOG("genboard: Write mapper %04x <- %02x\n", offset, data); + break; + + case MLTCLOCK: + // clock + m_clock->write(space, m_offset, data); + if (VERBOSE>7) LOG("genboard: Write clock %04x <- %02x\n", offset, data); + break; + + case MLTVIDEO: + // video + // ++++ ++-- ---- ---+ + // 1000 1100 0000 00c0 + // Initialize waitstate timer + m_video->write(space, m_offset, data, mem_mask); + if (VERBOSE>7) LOG("genboard: Write video %04x <- %02x\n", offset, data); + break; + + case MLTSPEECH: + // speech + // ++++ ++-- ---- ---+ + // 1001 0100 0000 0000 + // We need to add the address prefix bits + m_peribox->write(space, m_offset, data, mem_mask); + if (VERBOSE>7) LOG("genboard: Write speech <- %02x\n", data); + break; + + case MLTGROM: + // grom simulation + // ++++ ++-- ---- ---+ + // 1001 1100 0000 00c0 + write_grom(space, m_offset, data, mem_mask); + if (VERBOSE>7) LOG("genboard: Write GROM %04x <- %02x\n", offset, data); + break; + + case MLTSOUND: + // sound + // ++++ ++-- ---- ---+ + // 1000 0100 0000 0000 + m_sound->write(space, 0, data, mem_mask); + if (VERBOSE>7) LOG("genboard: Write sound <- %02x\n", data); + break; + + case MLTKEY: + case MLGKEY: + break; + + case MPGDRAM: + // DRAM write. One wait state. (only for normal Geneve) + m_dram[m_physaddr] = data; + if (VERBOSE>7) LOG("genboard: Write DRAM %04x (%06x) <- %02x\n", offset, m_physaddr, data); + break; + + case MPGEXP: + // On-board memory expansion for standard Geneve (never used) + if (VERBOSE>7) LOG("genboard: Write unmapped area %06x\n", m_physaddr); + break; + + case MPGEPROM: + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... + // Ignore EPROM write + if (VERBOSE>7) LOG("genboard: Write EPROM %04x (%06x) <- %02x, ignored\n", offset, m_physaddr, data); + break; + + case MPGSRAM: + if ((m_physaddr & m_sram_mask)==m_sram_val) + { + m_sram[m_physaddr & ~m_sram_mask] = data; + } + if (VERBOSE>7) LOG("genboard: Write SRAM %04x (%06x) <- %02x\n", offset, m_physaddr, data); + break; + + case MPGBOX: + m_physaddr = (m_physaddr & 0x0007ffff); // 19 bit address + if (VERBOSE>7) LOG("genboard: Write P-Box %04x (%06x) <- %02x\n", offset, m_physaddr, data); + m_peribox->write(space, m_physaddr, data, mem_mask); + break; + + case MPGMDRAM: + // DRAM. One wait state. + m_dram[m_physaddr] = data; + break; + + case MPGMEPROM: + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... + // Ignore EPROM write + break; + + case MPGMBOX: + // Route everything else to the P-Box + m_peribox->write(space, m_physaddr, data, mem_mask); + break; + } +} + +/* + Accept the address passed over the address bus and decode it appropriately. + This decoding will later be used in the READ/WRITE member functions. Also, + we initiate wait state creation here. +*/ +SETOFFSET_MEMBER( geneve_mapper_device::setoffset ) +{ int page; - if (m_peribox==NULL) return; // see above: prevent premature access + m_mapdecode = 0; + m_offset = offset; + m_physaddr = 0; - if (m_geneve_mode) + if (VERBOSE>7) LOG("genboard: setoffset = %04x\n", offset); + + // Premature access. The CPU reads the start vector before RESET. + if (m_eprom==NULL) return; + + if (m_read_mode) // got this from DBIN { - if ((offset & 0xfff1)==0xf100) + // Logical addresses + if (m_geneve_mode) { - // video - // ++++ ++++ ++++ ---+ - // 1111 0001 0000 .cc0 - m_video->write(space, offset, data, mem_mask); - - // 1 WS is always added; any pending video waitstates are canceled - m_video_waiting = false; - do_wait(1); - - // Initialize waitstate timer - // Create 14 waitstates (+3, experimenting) - if (m_video_waitstates) - do_wait(17); - - if (VERBOSE>7) LOG("genboard: Write video %04x <- %02x\n", offset, data); - return; - } - if ((offset & 0xfff8)==0xf110) - { - // mapper - m_map[offset & 0x0007] = data; - do_wait(1); - if (VERBOSE>7) LOG("genboard: Write mapper %04x <- %02x\n", offset, data); - return; - } - if ((offset & 0xfff1)==0xf120) - { - // sound - // ++++ ++++ ++++ ---+ - m_sound->write(space, 0, data, mem_mask); - - // Add 24 waitstates. This is an average value, as the - // waitstate generation seems to depend on an external timer of - // the sound chip - m_waitcount = 24; - m_ready(CLEAR_LINE); - if (VERBOSE>7) LOG("genboard: Write sound <- %02x\n", data); - return; - } - if ((offset & 0xfff0)==0xf130) - { - // clock - // ++++ ++++ ++++ ---- - m_clock->write(space, offset & 0x00f, data); - do_wait(1); - if (VERBOSE>7) LOG("genboard: Write clock %04x <- %02x\n", offset, data); - return; - } - } - else - { - // TI mode - if ((offset & 0xfff8)==0x8000) - { - // mapper - m_map[offset & 0x0007] = data; - do_wait(1); - if (VERBOSE>7) LOG("genboard: Write mapper %04x <- %02x\n", offset, data); - return; - } - // No key write at 8008 - if ((offset & 0xfff0)==0x8010) - { - // clock - m_clock->write(space, offset & 0x00f, data); - do_wait(1); - if (VERBOSE>7) LOG("genboard: Write clock %04x <- %02x\n", offset, data); - return; - } - if ((offset & 0xfc01)==0x8400) - { - // sound - // ++++ ++-- ---- ---+ - // 1000 0100 0000 0000 - - m_sound->write(space, 0, data, mem_mask); - // Add 24 waitstates. This is an approximation, as the - // waitstate generation seems to depend on an external timer of - // the sound chip - m_waitcount = 24; - m_ready(CLEAR_LINE); - if (VERBOSE>7) LOG("genboard: Write sound <- %02x\n", data); - return; - } - if ((offset & 0xfc01)==0x8c00) - { - // video - // ++++ ++-- ---- ---+ - // 1000 1100 0000 00c0 - // Initialize waitstate timer - m_video->write(space, offset, data, mem_mask); - - // 1 WS is always added; any pending video waitstates are canceled - m_video_waiting = false; - do_wait(1); - - // Initialize waitstate timer - // Create 14 waitstates (+3) - if (m_video_waitstates) - do_wait(17); - - if (VERBOSE>7) LOG("genboard: Write video %04x <- %02x\n", offset, data); - return; - } - if ((offset & 0xfc01)==0x9400) - { - // speech - // ++++ ++-- ---- ---+ - // 1001 0100 0000 0000 - // We need to add the address prefix bits - m_peribox->write(space, offset | ((m_genmod)? 0x170000 : 0x070000), data, mem_mask); - do_wait(1); - if (VERBOSE>7) LOG("genboard: Write speech <- %02x\n", data); - return; - } - if ((offset & 0xfc01)==0x9c00) - { - // grom simulation - // ++++ ++-- ---- ---+ - // 1001 1100 0000 00c0 - write_grom(space, offset, data, mem_mask); - do_wait(1); - if (VERBOSE>7) LOG("genboard: Write GROM %04x <- %02x\n", offset, data); - return; - } - } - - page = (offset & 0xe000) >> 13; - if (m_direct_mode) - { - physaddr = 0x1e0000; // points to boot eprom - } - else - { - if (!m_geneve_mode && page==3) - { - if (m_cartridge_size==0x4000) + // TODO: shortcut offset & 0xffc0 = 0xf100 + if ((offset & 0xfff5)==0xf100) { - // Writing to 0x6000 selects page 1, - // writing to 0x6002 selects page 2 - m_cartridge_secondpage = ((offset & 0x0002)!=0); - do_wait(1); - if (VERBOSE>7) LOG("genboard: Set cartridge page %02x\n", m_cartridge_secondpage); + // video + // ++++ ++++ ++++ -+-+ + // 1111 0001 0000 0000 + // 1111 0001 0000 0010 + // 1111 0001 0000 1000 + // 1111 0001 0000 1010 + // 1 WS is always added; any pending video wait states are canceled + m_video_waiting = false; + do_wait(1); + + // Initialize wait state timer + // Create 16 wait states (2 more than expected, experimenting) + if (m_video_waitstates) do_wait(16); + + m_mapdecode = MLGVIDEO; return; } - else + if ((offset & 0xfff8)==0xf110) { - // writing into cartridge rom space (no bankswitching) - if ((((offset & 0x1000)==0x0000) && !m_cartridge6_writable) - || (((offset & 0x1000)==0x1000) && !m_cartridge7_writable)) - { - if (VERBOSE>0) LOG("genboard: Writing to protected cartridge space %04x ignored\n", offset); - return; - } - else - // TODO: Check whether secondpage is really ignored - physaddr = 0x06c000; + // mapper + m_mapdecode = MLGMAPPER; + m_offset = m_offset & 0x0007; + do_wait(1); + return; + } + if ((offset & 0xfff8) == 0xf118) + { + // key + m_mapdecode = MLGKEY; + do_wait(1); + return; + } + if ((offset & 0xfff0)==0xf130) + { + // clock + // tests on the real machine showed that + // upper nibble is 0xf (probably because of the location at 0xf130?) + m_mapdecode = MLGCLOCK; + m_offset = m_offset & 0x000f; + do_wait(1); + return; } } else - physaddr = (m_map[page] << 13); - } - - physaddr |= offset & 0x1fff; - -// printf("write physaddr = %06x logaddr = %04x value = %02x\n", physaddr, offset, data); - - if (!m_genmod) - { - if ((physaddr & 0x180000)==0x000000) { - // DRAM write. One wait state. (only for normal Geneve) - m_dram[physaddr & 0x07ffff] = data; - do_wait(1); - if (VERBOSE>7) LOG("genboard: Write DRAM %04x (%06x) <- %02x\n", offset, physaddr, data); - return; - } - - if ((physaddr & 0x180000)==0x080000) - { - // On-board memory expansion for standard Geneve (never used) - do_wait(1); - if (VERBOSE>7) LOG("genboard: Write unmapped area %06x\n", physaddr); - return; - } - - if ((physaddr & 0x1e0000)==0x1e0000) - { - // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) - // mirrored for f0, f2, f4, ...; f1, f3, f5, ... - // Ignore EPROM write - do_wait(0); - if (VERBOSE>7) LOG("genboard: Write EPROM %04x (%06x) <- %02x, ignored\n", offset, physaddr, data); - return; - } - - if ((physaddr & 0x180000)==0x180000) - { - if ((physaddr & m_sram_mask)==m_sram_val) + if ((offset & 0xfff8)==0x8000) { - m_sram[physaddr & ~m_sram_mask] = data; + // mapper + m_mapdecode = MLTMAPPER; + m_offset = m_offset & 0x0007; + do_wait(1); + return; } - if (VERBOSE>7) LOG("genboard: Write SRAM %04x (%06x) <- %02x\n", offset, physaddr, data); - do_wait(0); - // Return in any case + if ((offset & 0xfff8)== 0x8008) + { + // key + m_mapdecode = MLTKEY; + do_wait(1); + return; + } + if ((offset & 0xfff0)==0x8010) + { + // clock + m_mapdecode = MLTCLOCK; + m_offset = m_offset & 0x000f; + do_wait(1); + return; + } + if ((offset & 0xfc01)==0x8800) + { + // video + // ++++ ++-- ---- ---+ + // 1000 1000 0000 00x0 + // 1 WS is always added; any pending video waitstates are canceled + m_mapdecode = MLTVIDEO; + m_video_waiting = false; + do_wait(1); + + // Initialize waitstate timer + // Create 14 waitstates (+2, see above) + if (m_video_waitstates) do_wait(16); + return; + } + if ((offset & 0xfc01)==0x9000) + { + // speech + // ++++ ++-- ---- ---+ + // 1001 0000 0000 0000 + // We need to add the address prefix bits + m_mapdecode = MLTSPEECH; + m_offset = offset | ((m_genmod)? 0x170000 : 0x070000); + m_peribox->setaddress_dbin(space, m_offset, m_read_mode); + do_wait(1); + return; + } + if ((offset & 0xfc01)==0x9800) + { + // grom simulation + // ++++ ++-- ---- ---+ + // 1001 1000 0000 00x0 + m_mapdecode = MLTGROM; + do_wait(1); + return; + } + } + // still here? Then go via mapping. + page = (offset & 0xe000) >> 13; + + // Determine physical address + if (m_direct_mode) + { + m_physaddr = 0x1e0000; // points to boot eprom + } + else + { + if (!m_geneve_mode && page==3) + { + if (m_cartridge_size==0x4000 && m_cartridge_secondpage) m_physaddr = 0x06e000; + else m_physaddr = 0x06c000; + } + else + { + m_physaddr = (m_map[page] << 13); + } + } + m_physaddr |= (offset & 0x1fff); + + if (!m_genmod) // Standard Geneve + { + if ((m_physaddr & 0x180000)==0x000000) + { + // DRAM. + m_physaddr = m_physaddr & 0x07ffff; + m_mapdecode = MPGDRAM; + do_wait(1); + return; + } + + if ((m_physaddr & 0x180000)==0x080000) + { + // On-board memory expansion for standard Geneve (never used) + m_mapdecode = MPGEXP; + do_wait(1); + return; + } + + if ((m_physaddr & 0x1e0000)==0x1e0000) + { + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... + m_mapdecode = MPGEPROM; + m_physaddr = m_physaddr & 0x003fff; + do_wait(0); + return; + } + + if ((m_physaddr & 0x180000)==0x180000) + { + m_mapdecode = MPGSRAM; + do_wait(0); + return; + } + + // Route everything else to the P-Box + // 0x000000-0x07ffff for the stock Geneve (AMC,AMB,AMA,A0 ...,A15) + // 0x000000-0x1fffff for the GenMod.(AME,AMD,AMC,AMB,AMA,A0 ...,A15) + // Add a wait state + do_wait(1); + m_mapdecode = MPGBOX; + + m_physaddr = (m_physaddr & 0x0007ffff); // 19 bit address (with AMA..AMC) + m_peribox->setaddress_dbin(space, m_physaddr, m_read_mode); return; } - // Route everything else to the P-Box - // Add a wait state + else + { + // GenMod mode + if ((m_timode) && ((m_physaddr & 0x180000)==0x000000)) + { + // DRAM. One wait state. + m_mapdecode = MPGMDRAM; + m_physaddr = m_physaddr & 0x07ffff; + if (!m_turbo) do_wait(1); + return; + } - // only AMA, AMB, AMC are used; AMD and AME are not used - physaddr = (physaddr & 0x0007ffff); // 19 bit address - if (VERBOSE>7) LOG("genboard: Write P-Box %04x (%06x) <- %02x\n", offset, physaddr, data); - m_peribox->write(space, physaddr, data, mem_mask); - do_wait(1); + if ((m_physaddr & 0x1e0000)==0x1e0000) + { + // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) + // mirrored for f0, f2, f4, ...; f1, f3, f5, ... + m_mapdecode = MPGMEPROM; + m_physaddr = m_physaddr & 0x003fff; + do_wait(0); + return; + } + + // Route everything else to the P-Box + m_physaddr = (m_physaddr & 0x001fffff); // 21 bit address for Genmod + m_mapdecode = MPGMBOX; + + if (!m_turbo) do_wait(1); + // Check: Are waitstates completely turned off for turbo mode, or + // merely the waitstates for DRAM memory access and box access? + + m_peribox->setaddress_dbin(space, m_physaddr, m_read_mode); + return; + } } else - { - // GenMod mode - if ((m_timode) && ((physaddr & 0x180000)==0x000000)) + { // Write access + // Logical addresses + if (m_geneve_mode) { - // DRAM. One wait state. - m_dram[physaddr & 0x07ffff] = data; - if (!m_turbo) do_wait(1); - return; + if ((offset & 0xfff1)==0xf100) + { + // 1 WS is always added; any pending video waitstates are canceled + m_mapdecode = MLGVIDEO; + m_video_waiting = false; + do_wait(1); + // Initialize waitstate timer + // Create 14 waitstates (+3, experimenting) + if (m_video_waitstates) do_wait(17); + return; + } + if ((offset & 0xfff8)==0xf110) + { + m_mapdecode = MLGMAPPER; + m_offset = m_offset & 0x0007; + do_wait(1); + return; + } + if ((offset & 0xfff1)==0xf120) + { + // Add 24 waitstates. This is an average value, as the + // waitstate generation seems to depend on an external timer of + // the sound chip + // TODO: do it properly with the use of READY + m_mapdecode = MLGSOUND; + do_wait(24); + return; + } + if ((offset & 0xfff0)==0xf130) + { + m_mapdecode = MLGCLOCK; + m_offset = m_offset & 0x00f; + do_wait(1); + return; + } + } + else + { + // TI mode + if ((offset & 0xfff8)==0x8000) + { + m_mapdecode = MLTMAPPER; + m_offset = m_offset & 0x0007; + do_wait(1); + return; + } + if ((offset & 0xfff0)==0x8010) + { + m_mapdecode = MLTCLOCK; + m_offset = m_offset & 0x00f; + do_wait(1); + return; + } + if ((offset & 0xfc01)==0x9c00) + { + m_mapdecode = MLTGROM; + do_wait(1); + return; + } + if ((offset & 0xfc01)==0x8400) + { + // Add 24 waitstates. This is an approximation, as the + // waitstate generation seems to depend on an external timer of + // the sound chip + // TODO: do it properly with the use of READY- + m_mapdecode = MLTSOUND; + do_wait(24); + return; + } + if ((offset & 0xfc01)==0x8c00) + { + // 1 WS is always added; any pending video waitstates are canceled + m_mapdecode = MLTVIDEO; + m_video_waiting = false; + do_wait(1); + + // Initialize waitstate timer + // Create 14 waitstates (+3) + if (m_video_waitstates) do_wait(17); + return; + } + + if ((offset & 0xfc01)==0x9400) + { + m_mapdecode = MLTSPEECH; + m_offset = m_offset | ((m_genmod)? 0x170000 : 0x070000); + m_peribox->setaddress_dbin(space, m_offset, m_read_mode); + do_wait(1); + return; + } } - if ((physaddr & 0x1e0000)==0x1e0000) + // Determine physical address + page = (m_offset & 0xe000) >> 13; + + if (m_direct_mode) { - // 1 111. ..xx xxxx xxxx xxxx on-board eprom (16K) - // mirrored for f0, f2, f4, ...; f1, f3, f5, ... - // Ignore EPROM write - if (!m_turbo) do_wait(1); - return; + m_physaddr = 0x1e0000; // points to boot eprom + } + else + { + if (!m_geneve_mode && page==3) + { + if (m_cartridge_size==0x4000) + { + m_cartridge_secondpage = ((m_offset & 0x0002)!=0); + if (VERBOSE>7) LOG("genboard: Set cartridge page %02x\n", m_cartridge_secondpage); + do_wait(1); + return; + } + else + { + // writing into cartridge rom space (no bankswitching) + if ((((m_offset & 0x1000)==0x0000) && !m_cartridge6_writable) + || (((m_offset & 0x1000)==0x1000) && !m_cartridge7_writable)) + { + if (VERBOSE>0) LOG("genboard: Writing to protected cartridge space %04x ignored\n", m_offset); + return; + } + else + // TODO: Check whether secondpage is really ignored + m_physaddr = 0x06c000; + } + } + else + m_physaddr = (m_map[page] << 13); + } + + m_physaddr |= m_offset & 0x1fff; + + if (!m_genmod) + { + if ((m_physaddr & 0x180000)==0x000000) + { + m_mapdecode = MPGDRAM; + m_physaddr = m_physaddr & 0x07ffff; + do_wait(1); + return; + } + if ((m_physaddr & 0x180000)==0x080000) + { + m_mapdecode = MPGEXP; + do_wait(1); + return; + } + + if ((m_physaddr & 0x1e0000)==0x1e0000) + { + m_mapdecode = MPGEPROM; + do_wait(0); // EPROM + return; + } + if ((m_physaddr & 0x180000)==0x180000) + { + m_mapdecode = MPGSRAM; + do_wait(0); // SRAM + return; + } + + // Route everything else to the P-Box + // Add a wait state + + // only AMA, AMB, AMC are used; AMD and AME are not used + m_mapdecode = MPGBOX; + m_physaddr = (m_physaddr & 0x0007ffff); // 19 bit address + m_peribox->setaddress_dbin(space, m_physaddr, m_read_mode); + do_wait(1); + } + else + { + // GenMod mode + if ((m_physaddr & 0x1e0000)==0x1e0000) + { // EPROM, ignore + m_mapdecode = MPGMEPROM; + do_wait(0); + return; + } + + if (m_timode && ((m_physaddr & 0x180000)==0x000000)) + { + m_mapdecode = MPGMDRAM; + m_physaddr = m_physaddr & 0x07ffff; + if (!m_turbo) do_wait(1); + return; + } + + // Route everything else to the P-Box + m_mapdecode = MPGMBOX; + m_physaddr = (m_physaddr & 0x001fffff); // 21 bit address for Genmod + m_peribox->setaddress_dbin(space, m_physaddr, m_read_mode); + if (!m_turbo) do_wait(1); } - // Route everything else to the P-Box - physaddr = (physaddr & 0x001fffff); // 21 bit address for Genmod - m_peribox->write(space, physaddr, data, mem_mask); - if (!m_turbo) do_wait(1); } } @@ -816,11 +1038,21 @@ void geneve_mapper_device::clock_in(int clock) { if (clock==ASSERT_LINE && m_waitcount!=0) { + if (VERBOSE>5) LOG("genboard: clock\n"); m_waitcount--; if (m_waitcount==0) m_ready(ASSERT_LINE); } } +/* + We need the DBIN line for the setoffset operation. +*/ +void geneve_mapper_device::dbin(int state) +{ + m_read_mode = (state==ASSERT_LINE); + if (VERBOSE>7) LOG("genboard: dbin = %02x\n", m_read_mode? 1:0); +} + /*** DEVICE LIFECYCLE FUNCTIONS ***/ void geneve_mapper_device::device_start() @@ -858,6 +1090,7 @@ void geneve_mapper_device::device_reset() m_extra_waitstates = false; m_video_waitstates = true; m_video_waiting = false; + m_read_mode = false; m_geneve_mode =false; m_direct_mode = true; diff --git a/src/mess/machine/ti99/genboard.h b/src/mess/machine/ti99/genboard.h index 3186fa99682..b04d7376779 100644 --- a/src/mess/machine/ti99/genboard.h +++ b/src/mess/machine/ti99/genboard.h @@ -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; diff --git a/src/mess/machine/ti99/mapper8.c b/src/mess/machine/ti99/mapper8.c index 0ff73b2fa71..627c3b155a6 100644 --- a/src/mess/machine/ti99/mapper8.c +++ b/src/mess/machine/ti99/mapper8.c @@ -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]); } } } diff --git a/src/mess/machine/ti99/peribox.c b/src/mess/machine/ti99/peribox.c index 17849f428c3..95f93b4441b 100644 --- a/src/mess/machine/ti99/peribox.c +++ b/src/mess/machine/ti99/peribox.c @@ -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); diff --git a/src/mess/machine/ti99/peribox.h b/src/mess/machine/ti99/peribox.h index ca6aaa6ae7f..0ed7efa7b1c 100644 --- a/src/mess/machine/ti99/peribox.h +++ b/src/mess/machine/ti99/peribox.h @@ -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); diff --git a/src/mess/machine/ti99/spchsyn.c b/src/mess/machine/ti99/spchsyn.c index e1a9fdffb45..46746d81041 100644 --- a/src/mess/machine/ti99/spchsyn.c +++ b/src/mess/machine/ti99/spchsyn.c @@ -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("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 ) diff --git a/src/mess/machine/ti99/spchsyn.h b/src/mess/machine/ti99/spchsyn.h index 0af706eb69e..10fa6db5ef9 100644 --- a/src/mess/machine/ti99/spchsyn.h +++ b/src/mess/machine/ti99/spchsyn.h @@ -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 diff --git a/src/mess/machine/ti99/ti99defs.h b/src/mess/machine/ti99/ti99defs.h index 45732d68b19..33cc50c679e 100644 --- a/src/mess/machine/ti99/ti99defs.h +++ b/src/mess/machine/ti99/ti99defs.h @@ -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 ) { }; }; /****************************************************************************