mirror of
https://github.com/holub/mame
synced 2025-04-18 22:49:58 +03:00
ti99: Again one indirection less; dropped the videowrp and moved the v9938 on the EVPC board.
This commit is contained in:
parent
9829c978c7
commit
c7aeff7d6d
@ -2076,8 +2076,6 @@ if (BUSES["TI99X"]~=null) then
|
||||
MAME_DIR .. "src/devices/bus/ti99x/mecmouse.cpp",
|
||||
MAME_DIR .. "src/devices/bus/ti99x/mecmouse.h",
|
||||
MAME_DIR .. "src/devices/bus/ti99x/ti99defs.h",
|
||||
MAME_DIR .. "src/devices/bus/ti99x/videowrp.cpp",
|
||||
MAME_DIR .. "src/devices/bus/ti99x/videowrp.h",
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -1,39 +1,99 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Michael Zapf
|
||||
/****************************************************************************
|
||||
SNUG Enhanced Video Processor Card (evpc)
|
||||
based on v9938 (may also be equipped with v9958)
|
||||
Can be used with TI-99/4A as an add-on card; internal VDP must be removed
|
||||
SNUG Enhanced Video Processor Card (EVPC)
|
||||
|
||||
This is an expansion card with an own v9938 video processor on board.
|
||||
Later releases (EVPC2) can also be equipped with a v9958.
|
||||
|
||||
The EVPC is intended to be used
|
||||
1. with the TI-99/4A console
|
||||
2. with the SGCPU
|
||||
|
||||
For option 1, the console-internal VDP (TMS9928A) must be removed. This,
|
||||
however, raises a problem, because the video interrupt must now be send
|
||||
from the EVPC in the Peripheral Expansion Box to the console, but there is
|
||||
no line in the PEB cable for this purpose.
|
||||
|
||||
To solve this issue, a separate cable is led from the EVPC to the console
|
||||
which delivers the video interrupt, and also the GROM clock which is also
|
||||
lost due to the removal of the internal VDP.
|
||||
|
||||
The SGCPU requires this card, as it does not offer any video processor.
|
||||
In this configuration, the video interrupt cable is not required.
|
||||
|
||||
Also, the SGCPU does not offer a socket for the sound chip of the TI
|
||||
console, and accordingly, the EVPC also gives the sound chip a new home.
|
||||
Thus we assume that in the TI console (option 1) the sound chip has
|
||||
also been removed.
|
||||
|
||||
Important note: The DSR (firmware) of the EVPC expects a memory expansion
|
||||
to be present; otherwise, the configuration (using CALL EVPC) will crash.
|
||||
There is no warning if the 32K expansion is not present.
|
||||
|
||||
The SGCPU ("TI-99/4P") only runs with EVPC.
|
||||
Michael Zapf
|
||||
|
||||
October 2010: Rewritten as device
|
||||
February 2012: Rewritten as class
|
||||
|
||||
FIXME: Locks up on startup when HFDC is present. This can be avoided
|
||||
by using another controller (like bwg) or doing a soft reset.
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include "evpc.h"
|
||||
|
||||
#define EVPC_CRU_BASE 0x1400
|
||||
#define VERBOSE 1
|
||||
#define LOG logerror
|
||||
|
||||
#define TRACE_ADDRESS 0
|
||||
#define TRACE_CRU 0
|
||||
#define TRACE_MEM 0
|
||||
|
||||
#define NOVRAM_SIZE 256
|
||||
|
||||
snug_enhanced_video_device::snug_enhanced_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: ti_expansion_card_device(mconfig, TI99_EVPC, "SNUG Enhanced Video Processor Card", tag, owner, clock, "ti99_evpc", __FILE__),
|
||||
device_nvram_interface(mconfig, *this),
|
||||
m_dsrrom(nullptr),
|
||||
m_RAMEN(false),
|
||||
m_dsr_page(0),
|
||||
m_novram(nullptr)
|
||||
m_inDsrArea(false),
|
||||
m_novram_accessed(false),
|
||||
m_palette_accessed(false),
|
||||
m_RAMEN(false),
|
||||
m_dsrrom(nullptr),
|
||||
m_novram(nullptr),
|
||||
m_video(*this, VDP_TAG),
|
||||
m_sound(*this, TISOUNDCHIP_TAG)
|
||||
{
|
||||
}
|
||||
|
||||
SETADDRESS_DBIN_MEMBER( snug_enhanced_video_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;
|
||||
|
||||
if (TRACE_ADDRESS) logerror("set address %04x, %s\n", offset, (state==ASSERT_LINE)? "read" : "write");
|
||||
|
||||
m_address = offset;
|
||||
bool reading = (state==ASSERT_LINE);
|
||||
int offbase = (m_address & 0xfc01);
|
||||
|
||||
// Sound
|
||||
m_sound_accessed = ((m_address & 0xff01)==0x8400) && !reading;
|
||||
|
||||
// Video space
|
||||
// 8800 / 8802 / 8804 / 8806
|
||||
// 8c00 / 8c02 / 8c04 / 8c06
|
||||
//
|
||||
// Bits 1000 1w00 0000 0xx0
|
||||
// Mask 1111 1000 0000 0001
|
||||
m_video_accessed = ((offbase==0x8800) && reading) || ((offbase==0x8c00) && !reading);
|
||||
|
||||
// Read a byte in evpc DSR space
|
||||
// 0x4000 - 0x5eff DSR (paged)
|
||||
// 0x5f00 - 0x5fef NOVRAM
|
||||
// 0x5ff0 - 0x5fff Palette
|
||||
m_inDsrArea = ((m_address & 0xe000)==0x4000);
|
||||
m_novram_accessed = ((m_address & 0xff00)==0x5f00);
|
||||
m_palette_accessed = ((m_address & 0xfff0)==0x5ff0);
|
||||
|
||||
// Note that we check the selection in reverse order so that the overlap is avoided
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// nvram_default - called to initialize NVRAM to
|
||||
// its default state
|
||||
@ -64,85 +124,80 @@ void snug_enhanced_video_device::nvram_write(emu_file &file)
|
||||
file.write(m_novram.get(), NOVRAM_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Read a byte in evpc DSR space
|
||||
Read a byte in evpc DSR space, NOVRAM, Palette, or video
|
||||
0x4000 - 0x5eff DSR (paged)
|
||||
0x5f00 - 0x5fef NOVRAM
|
||||
0x5ff0 - 0x5fff Palette
|
||||
0x5ff0 - 0x5fff Palette (5ff0, 5ff2, 5ff4, 5ff6)
|
||||
*/
|
||||
READ8Z_MEMBER(snug_enhanced_video_device::readz)
|
||||
{
|
||||
if (m_selected)
|
||||
if (m_selected && m_inDsrArea)
|
||||
{
|
||||
if ((offset & m_select_mask)==m_select_value)
|
||||
if (m_palette_accessed)
|
||||
{
|
||||
if ((offset & 0x1ff0)==0x1ff0) // Palette control
|
||||
switch (m_address & 0x000f)
|
||||
{
|
||||
switch (offset & 0x000f)
|
||||
{
|
||||
case 0:
|
||||
/* Palette Read Address Register */
|
||||
*value = m_palette.write_index;
|
||||
break;
|
||||
case 0:
|
||||
// Palette Read Address Register
|
||||
*value = m_palette.write_index;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* Palette Read Color Value */
|
||||
if (m_palette.read)
|
||||
{
|
||||
switch (m_palette.state)
|
||||
{
|
||||
case 0:
|
||||
*value = m_palette.color[m_palette.read_index].red;
|
||||
break;
|
||||
case 1:
|
||||
*value = m_palette.color[m_palette.read_index].green;
|
||||
break;
|
||||
case 2:
|
||||
*value = m_palette.color[m_palette.read_index].blue;
|
||||
break;
|
||||
}
|
||||
m_palette.state++;
|
||||
if (m_palette.state == 3)
|
||||
{
|
||||
m_palette.state = 0;
|
||||
m_palette.read_index++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
/* Palette Read Pixel Mask */
|
||||
*value = m_palette.mask;
|
||||
break;
|
||||
case 6:
|
||||
/* Palette Read Address Register for Color Value */
|
||||
if (m_palette.read)
|
||||
*value = 0;
|
||||
else
|
||||
*value = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((offset & 0x1f00)==0x1f00)
|
||||
case 2:
|
||||
// Palette Read Color Value
|
||||
if (m_palette.read)
|
||||
{
|
||||
if (m_RAMEN) // NOVRAM hides DSR
|
||||
switch (m_palette.state)
|
||||
{
|
||||
*value = m_novram[offset & 0x00ff];
|
||||
case 0:
|
||||
*value = m_palette.color[m_palette.read_index].red;
|
||||
break;
|
||||
case 1:
|
||||
*value = m_palette.color[m_palette.read_index].green;
|
||||
break;
|
||||
case 2:
|
||||
*value = m_palette.color[m_palette.read_index].blue;
|
||||
break;
|
||||
}
|
||||
else // DSR
|
||||
m_palette.state++;
|
||||
if (m_palette.state == 3)
|
||||
{
|
||||
*value = m_dsrrom[(offset&0x1fff) | (m_dsr_page<<13)];
|
||||
m_palette.state = 0;
|
||||
m_palette.read_index++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// Palette Read Pixel Mask
|
||||
*value = m_palette.mask;
|
||||
break;
|
||||
case 6:
|
||||
// Palette Read Address Register for Color Value
|
||||
if (m_palette.read)
|
||||
*value = 0;
|
||||
else
|
||||
{
|
||||
*value = m_dsrrom[(offset&0x1fff) | (m_dsr_page<<13)];
|
||||
}
|
||||
*value = 3;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_novram_accessed && m_RAMEN)
|
||||
{
|
||||
// NOVRAM
|
||||
*value = m_novram[offset & 0x00ff];
|
||||
return;
|
||||
}
|
||||
|
||||
// DSR space
|
||||
*value = m_dsrrom[(offset & 0x1fff) | (m_dsr_page<<13)];
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_video_accessed)
|
||||
{
|
||||
*value = m_video->read(space, m_address>>1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,82 +205,87 @@ READ8Z_MEMBER(snug_enhanced_video_device::readz)
|
||||
Write a byte in evpc DSR space
|
||||
0x4000 - 0x5eff DSR (paged)
|
||||
0x5f00 - 0x5fef NOVRAM
|
||||
0x5ff0 - 0x5fff Palette
|
||||
0x5ff0 - 0x5fff Palette (5ff8, 5ffa, 5ffc, 5ffe)
|
||||
*/
|
||||
WRITE8_MEMBER(snug_enhanced_video_device::write)
|
||||
{
|
||||
if (m_selected)
|
||||
if (m_selected && m_inDsrArea)
|
||||
{
|
||||
if ((offset & m_select_mask)==m_select_value)
|
||||
if (m_palette_accessed)
|
||||
{
|
||||
if ((offset & 0x1ff0)==0x1ff0)
|
||||
// Palette
|
||||
if (TRACE_MEM) logerror("palette write %04x <- %02x\n", offset&0xffff, data);
|
||||
switch (m_address & 0x000f)
|
||||
{
|
||||
/* PALETTE */
|
||||
if (VERBOSE>5) LOG("palette write %04x <- %02x\n", offset&0xffff, data);
|
||||
switch (offset & 0x000f)
|
||||
case 0x08:
|
||||
// Palette Write Address Register
|
||||
if (TRACE_MEM) logerror("EVPC palette address write (for write access)\n");
|
||||
m_palette.write_index = data;
|
||||
m_palette.state = 0;
|
||||
m_palette.read = 0;
|
||||
break;
|
||||
|
||||
case 0x0a:
|
||||
// Palette Write Color Value
|
||||
if (TRACE_MEM) logerror("EVPC palette color write\n");
|
||||
if (!m_palette.read)
|
||||
{
|
||||
case 0x08:
|
||||
/* Palette Write Address Register */
|
||||
if (VERBOSE>5) LOG("EVPC palette address write (for write access)\n");
|
||||
m_palette.write_index = data;
|
||||
m_palette.state = 0;
|
||||
m_palette.read = 0;
|
||||
break;
|
||||
|
||||
case 0x0a:
|
||||
/* Palette Write Color Value */
|
||||
if (VERBOSE>5) LOG("EVPC palette color write\n");
|
||||
if (!m_palette.read)
|
||||
switch (m_palette.state)
|
||||
{
|
||||
switch (m_palette.state)
|
||||
{
|
||||
case 0:
|
||||
m_palette.color[m_palette.write_index].red = data;
|
||||
break;
|
||||
case 1:
|
||||
m_palette.color[m_palette.write_index].green = data;
|
||||
break;
|
||||
case 2:
|
||||
m_palette.color[m_palette.write_index].blue = data;
|
||||
break;
|
||||
}
|
||||
m_palette.state++;
|
||||
if (m_palette.state == 3)
|
||||
{
|
||||
m_palette.state = 0;
|
||||
m_palette.write_index++;
|
||||
}
|
||||
//evpc_palette.dirty = 1;
|
||||
case 0:
|
||||
m_palette.color[m_palette.write_index].red = data;
|
||||
break;
|
||||
case 1:
|
||||
m_palette.color[m_palette.write_index].green = data;
|
||||
break;
|
||||
case 2:
|
||||
m_palette.color[m_palette.write_index].blue = data;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0c:
|
||||
/* Palette Write Pixel Mask */
|
||||
if (VERBOSE>5) LOG("EVPC palette mask write\n");
|
||||
m_palette.mask = data;
|
||||
break;
|
||||
|
||||
case 0x0e:
|
||||
/* Palette Write Address Register for Color Value */
|
||||
if (VERBOSE>5) LOG("EVPC palette address write (for read access)\n");
|
||||
m_palette.read_index = data;
|
||||
m_palette.state = 0;
|
||||
m_palette.read = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((offset & 0x1f00)==0x1f00)
|
||||
{
|
||||
if (m_RAMEN)
|
||||
m_palette.state++;
|
||||
if (m_palette.state == 3)
|
||||
{
|
||||
// NOVRAM
|
||||
m_novram[offset & 0x00ff] = data;
|
||||
m_palette.state = 0;
|
||||
m_palette.write_index++;
|
||||
}
|
||||
//evpc_palette.dirty = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0c:
|
||||
// Palette Write Pixel Mask
|
||||
if (TRACE_MEM) logerror("EVPC palette mask write\n");
|
||||
m_palette.mask = data;
|
||||
break;
|
||||
|
||||
case 0x0e:
|
||||
// Palette Write Address Register for Color Value
|
||||
if (TRACE_MEM) logerror("EVPC palette address write (for read access)\n");
|
||||
m_palette.read_index = data;
|
||||
m_palette.state = 0;
|
||||
m_palette.read = 1;
|
||||
break;
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_novram_accessed && m_RAMEN)
|
||||
{
|
||||
// NOVRAM
|
||||
m_novram[offset & 0x00ff] = data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_video_accessed)
|
||||
{
|
||||
m_video->write(space, m_address>>1, data);
|
||||
}
|
||||
|
||||
if (m_sound_accessed)
|
||||
{
|
||||
m_sound->write(space, 0, data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,7 +333,7 @@ WRITE8_MEMBER(snug_enhanced_video_device::cruwrite)
|
||||
{
|
||||
case 0:
|
||||
m_selected = (data!=0);
|
||||
if (VERBOSE>4) LOG("evpc: Map DSR = %d\n", m_selected);
|
||||
if (TRACE_CRU) logerror("Map DSR = %d\n", m_selected);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
@ -309,15 +369,23 @@ WRITE8_MEMBER(snug_enhanced_video_device::cruwrite)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
READY line for the sound chip
|
||||
*/
|
||||
WRITE_LINE_MEMBER( snug_enhanced_video_device::ready_line )
|
||||
{
|
||||
m_slot->set_ready(state);
|
||||
}
|
||||
|
||||
void snug_enhanced_video_device::device_start()
|
||||
{
|
||||
m_dsrrom = memregion(DSRROM)->base();
|
||||
m_novram = std::make_unique<UINT8[]>(NOVRAM_SIZE);
|
||||
m_console_conn = downcast<evpc_clock_connector*>(machine().device(EVPC_CONN_TAG));
|
||||
}
|
||||
|
||||
void snug_enhanced_video_device::device_reset()
|
||||
{
|
||||
if (VERBOSE>5) LOG("evpc: reset\n");
|
||||
m_select_mask = 0x7e000;
|
||||
m_select_value = 0x74000;
|
||||
m_dsr_page = 0;
|
||||
@ -330,11 +398,36 @@ void snug_enhanced_video_device::device_stop()
|
||||
m_novram = nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
This is the extra cable running from the EVPC card right into the TI console.
|
||||
It delivers the VDP interrupt and the GROM clock.
|
||||
|
||||
For the SGCPU, the signal is delivered by the LCP line.
|
||||
*/
|
||||
WRITE_LINE_MEMBER( snug_enhanced_video_device::video_interrupt_in )
|
||||
{
|
||||
if (m_console_conn != nullptr) m_console_conn->vclock_line(state);
|
||||
else m_slot->lcp_line(state);
|
||||
}
|
||||
|
||||
ROM_START( ti99_evpc )
|
||||
ROM_REGION(0x10000, DSRROM, 0)
|
||||
ROM_LOAD("evpcdsr.bin", 0, 0x10000, CRC(a062b75d) SHA1(6e8060f86e3bb9c36f244d88825e3fe237bfe9a9)) /* evpc DSR ROM */
|
||||
ROM_END
|
||||
|
||||
MACHINE_CONFIG_FRAGMENT( ti99_evpc )
|
||||
// video hardware
|
||||
MCFG_V9938_ADD(VDP_TAG, SCREEN_TAG, 0x20000, XTAL_21_4772MHz) /* typical 9938 clock, not verified */
|
||||
MCFG_V99X8_INTERRUPT_CALLBACK(WRITELINE(snug_enhanced_video_device, video_interrupt_in))
|
||||
MCFG_V99X8_SCREEN_ADD_NTSC(SCREEN_TAG, VDP_TAG, XTAL_21_4772MHz)
|
||||
|
||||
// Sound hardware
|
||||
MCFG_SPEAKER_STANDARD_MONO("sound_out")
|
||||
MCFG_SOUND_ADD(TISOUNDCHIP_TAG, SN94624, 3579545/8) /* 3.579545 MHz */
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "sound_out", 0.75)
|
||||
MCFG_SN76496_READY_HANDLER( WRITELINE(snug_enhanced_video_device, ready_line) )
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/*
|
||||
Input ports for the EPVC
|
||||
*/
|
||||
@ -370,4 +463,9 @@ ioport_constructor snug_enhanced_video_device::device_input_ports() const
|
||||
return INPUT_PORTS_NAME(ti99_evpc);
|
||||
}
|
||||
|
||||
machine_config_constructor snug_enhanced_video_device::device_mconfig_additions() const
|
||||
{
|
||||
return MACHINE_CONFIG_NAME( ti99_evpc );
|
||||
}
|
||||
|
||||
const device_type TI99_EVPC = &device_creator<snug_enhanced_video_device>;
|
||||
|
@ -17,6 +17,9 @@
|
||||
|
||||
#include "emu.h"
|
||||
#include "peribox.h"
|
||||
#include "video/v9938.h"
|
||||
#include "sound/sn76496.h"
|
||||
#include "bus/ti99x/ti99defs.h"
|
||||
|
||||
extern const device_type TI99_EVPC;
|
||||
|
||||
@ -35,28 +38,45 @@ public:
|
||||
snug_enhanced_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
DECLARE_READ8Z_MEMBER(readz) override;
|
||||
DECLARE_WRITE8_MEMBER(write) override;
|
||||
DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin) override;
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( ready_line );
|
||||
|
||||
DECLARE_READ8Z_MEMBER(crureadz) override;
|
||||
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
||||
DECLARE_WRITE_LINE_MEMBER( video_interrupt_in );
|
||||
|
||||
protected:
|
||||
virtual void device_start(void) override;
|
||||
virtual void device_reset(void) override;
|
||||
virtual void device_stop(void) override;
|
||||
void device_start(void) override;
|
||||
void device_reset(void) override;
|
||||
void device_stop(void) override;
|
||||
|
||||
virtual const rom_entry *device_rom_region() const override;
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
machine_config_constructor device_mconfig_additions() const override;
|
||||
|
||||
void nvram_default() override;
|
||||
void nvram_read(emu_file &file) override;
|
||||
void nvram_write(emu_file &file) override;
|
||||
|
||||
private:
|
||||
UINT8* m_dsrrom;
|
||||
bool m_RAMEN;
|
||||
int m_dsr_page;
|
||||
std::unique_ptr<UINT8[]> m_novram; /* NOVRAM area */
|
||||
evpc_palette m_palette;
|
||||
int m_address;
|
||||
int m_dsr_page;
|
||||
bool m_inDsrArea;
|
||||
bool m_novram_accessed;
|
||||
bool m_palette_accessed;
|
||||
bool m_RAMEN;
|
||||
bool m_sound_accessed;
|
||||
bool m_video_accessed;
|
||||
|
||||
UINT8* m_dsrrom;
|
||||
|
||||
std::unique_ptr<UINT8[]> m_novram; // NOVRAM area
|
||||
|
||||
evpc_palette m_palette;
|
||||
required_device<v9938_device> m_video;
|
||||
required_device<sn76496_base_device> m_sound;
|
||||
evpc_clock_connector* m_console_conn;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -127,6 +127,7 @@
|
||||
#define TRACE_DSR 0
|
||||
#define TRACE_BANKING 0
|
||||
#define TRACE_CRU 0
|
||||
#define TRACE_ADDRESS 0
|
||||
#define TRACE_READ 0
|
||||
#define TRACE_WRITE 0
|
||||
#define TRACE_IGNORE 0
|
||||
@ -165,7 +166,7 @@ WRITE8_MEMBER(snug_high_speed_gpl_device::cruwrite)
|
||||
{
|
||||
if (data != 0)
|
||||
{
|
||||
if (TRACE_CRU) logerror("%s: Supercart cru setting %04x\n", tag(), offset);
|
||||
if (TRACE_CRU) logerror("Supercart cru setting %04x\n", offset);
|
||||
m_current_bank = (offset-0x0802)>>2;
|
||||
}
|
||||
return;
|
||||
@ -179,15 +180,15 @@ WRITE8_MEMBER(snug_high_speed_gpl_device::cruwrite)
|
||||
{
|
||||
case 0:
|
||||
m_dsr_enabled = (data != 0);
|
||||
if (TRACE_CRU) logerror("%s: Set dsr_enabled=%x\n", tag(), data);
|
||||
if (TRACE_CRU) logerror("Set dsr_enabled=%x\n", data);
|
||||
break;
|
||||
case 1:
|
||||
m_gram_enabled = (data != 0);
|
||||
if (TRACE_CRU) logerror("%s: Set gram_enabled=%x\n", tag(), data);
|
||||
if (TRACE_CRU) logerror("Set gram_enabled=%x\n", data);
|
||||
break;
|
||||
case 2:
|
||||
m_bank_inhibit = (data != 0);
|
||||
if (TRACE_CRU) logerror("%s: Set bank_inhibit=%x\n", tag(), data);
|
||||
if (TRACE_CRU) logerror("Set bank_inhibit=%x\n", data);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
@ -199,34 +200,34 @@ WRITE8_MEMBER(snug_high_speed_gpl_device::cruwrite)
|
||||
m_dsr_page |= (1 << (bit-3));
|
||||
else
|
||||
m_dsr_page &= ~(1 << (bit-3));
|
||||
if (TRACE_CRU) logerror("%s: Set dsr_page=%d\n", tag(), m_dsr_page);
|
||||
if (TRACE_CRU) logerror("Set dsr_page=%d\n", m_dsr_page);
|
||||
break;
|
||||
case 9:
|
||||
m_card_enabled = data;
|
||||
if (TRACE_CRU) logerror("%s: Set card_enabled=%x\n", tag(), data);
|
||||
if (TRACE_CRU) logerror("Set card_enabled=%x\n", data);
|
||||
break;
|
||||
case 10:
|
||||
m_write_enabled = data;
|
||||
if (TRACE_CRU) logerror("%s: Set write_enabled=%x\n", tag(), data);
|
||||
if (TRACE_CRU) logerror("Set write_enabled=%x\n", data);
|
||||
break;
|
||||
case 11:
|
||||
m_supercart_enabled = data;
|
||||
// CHECK: Do we have to reset the bank?
|
||||
if (TRACE_CRU) logerror("%s: Set supercart_enabled=%x\n", tag(), data);
|
||||
if (TRACE_CRU) logerror("Set supercart_enabled=%x\n", data);
|
||||
break;
|
||||
case 12:
|
||||
m_led_on = data;
|
||||
if (TRACE_CRU) logerror("%s: Set led_on=%x\n", tag(), data);
|
||||
if (TRACE_CRU) logerror("Set led_on=%x\n", data);
|
||||
break;
|
||||
case 13:
|
||||
break;
|
||||
case 14:
|
||||
m_mbx_enabled = data;
|
||||
if (TRACE_CRU) logerror("%s: Set mbx_enabled=%x\n", tag(), data);
|
||||
if (TRACE_CRU) logerror("Set mbx_enabled=%x\n", data);
|
||||
break;
|
||||
case 15:
|
||||
m_ram_enabled = data;
|
||||
if (TRACE_CRU) logerror("%s: Set ram_enabled=%x\n", tag(), data);
|
||||
if (TRACE_CRU) logerror("Set ram_enabled=%x\n", data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -279,7 +280,7 @@ void snug_high_speed_gpl_device::dsrspace_readz(address_space& space, offs_t off
|
||||
if (m_dsr_enabled)
|
||||
{
|
||||
*value = m_dsr_eeprom->read(space, (offset & 0x1fff) | (m_dsr_page<<13), mem_mask);
|
||||
if (TRACE_READ) logerror("%s: read dsr %04x[%02x] -> %02x\n", tag(), offset, m_dsr_page, *value);
|
||||
if (TRACE_READ) logerror("read dsr %04x[%02x] -> %02x\n", offset, m_dsr_page, *value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,14 +291,14 @@ void snug_high_speed_gpl_device::cartspace_readz(address_space& space, offs_t of
|
||||
{
|
||||
if (!m_card_enabled || m_flash_mode)
|
||||
{
|
||||
if (TRACE_IGNORE) logerror("%s: cartridge space read ignored (enable=%d, flash_mode=%d)\n", tag(), m_card_enabled, m_flash_mode);
|
||||
if (TRACE_IGNORE) logerror("cartridge space read ignored (enable=%d, flash_mode=%d)\n", m_card_enabled, m_flash_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_module_bank < 16)
|
||||
{
|
||||
*value = m_rom6_eeprom->read(space, (offset & 0x1fff) | (m_current_bank<<13) | (m_current_grom_port<<15), mem_mask);
|
||||
if (TRACE_READ) logerror("%s: cartridge space read %04x -> %02x\n", tag(), offset, *value);
|
||||
if (TRACE_READ) logerror("cartridge space read %04x -> %02x\n", offset, *value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -307,7 +308,7 @@ void snug_high_speed_gpl_device::cartspace_readz(address_space& space, offs_t of
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("%s: unknown 0x6000 port\n", tag());
|
||||
logerror("unknown 0x6000 port\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -356,7 +357,7 @@ void snug_high_speed_gpl_device::grom_readz(address_space& space, offs_t offset,
|
||||
{
|
||||
*value = m_gram_memory[m_grom_address | (port<<16)];
|
||||
m_module_bank = port + 16;
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: GRAM read access at %04x (GRMENA=1) - switch to bank %d\n", tag(), offset & 0xffff, m_module_bank);
|
||||
if (TRACE_PORT) if (bNew) logerror("GRAM read access at %04x (GRMENA=1) - switch to bank %d\n", offset & 0xffff, m_module_bank);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -366,7 +367,7 @@ void snug_high_speed_gpl_device::grom_readz(address_space& space, offs_t offset,
|
||||
{
|
||||
*value = m_grom_a_eeprom->read(space, m_grom_address | (port<<16), mem_mask);
|
||||
m_module_bank = port;
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: GROM read access at %04x - switch to bank %d\n", tag(), offset & 0xffff, m_module_bank);
|
||||
if (TRACE_PORT) if (bNew) logerror("GROM read access at %04x - switch to bank %d\n", offset & 0xffff, m_module_bank);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -375,7 +376,7 @@ void snug_high_speed_gpl_device::grom_readz(address_space& space, offs_t offset,
|
||||
{
|
||||
*value = m_grom_b_eeprom->read(space, m_grom_address | ((port-8)<<16), mem_mask);
|
||||
m_module_bank = port;
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: GROM read access at %04x - switch to bank %d\n", tag(), offset & 0xffff, m_module_bank);
|
||||
if (TRACE_PORT) if (bNew) logerror("GROM read access at %04x - switch to bank %d\n", offset & 0xffff, m_module_bank);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -385,7 +386,7 @@ void snug_high_speed_gpl_device::grom_readz(address_space& space, offs_t offset,
|
||||
// DSR banks 0-63 (8 KiB per bank, 8 banks per port)
|
||||
*value = m_dsr_eeprom->read(space, m_grom_address | ((port-16)<<16), mem_mask);
|
||||
// Don't change the module port
|
||||
if (TRACE_DSR) if (bNew) logerror("%s: read access to DSR bank %d-%d (%04x)\n", tag(), (port-16)<<3, ((port-16)<<3)+7, offset);
|
||||
if (TRACE_DSR) if (bNew) logerror("read access to DSR bank %d-%d (%04x)\n", (port-16)<<3, ((port-16)<<3)+7, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -395,7 +396,7 @@ void snug_high_speed_gpl_device::grom_readz(address_space& space, offs_t offset,
|
||||
// Each ROM6 is available as 4 (sub)banks (switchable via 6000, 6002, 6004, 6006)
|
||||
// Accordingly, each port has two complete sets
|
||||
*value = m_rom6_eeprom->read(space, m_grom_address | ((port-24)<<16), mem_mask);
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: ROM6 read access for module bank %d-%d (%04x)\n", tag(), (port-24)<<1, ((port-24)<<1)+1, offset & 0xffff);
|
||||
if (TRACE_PORT) if (bNew) logerror("ROM6 read access for module bank %d-%d (%04x)\n", (port-24)<<1, ((port-24)<<1)+1, offset & 0xffff);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -404,7 +405,7 @@ void snug_high_speed_gpl_device::grom_readz(address_space& space, offs_t offset,
|
||||
{
|
||||
*value = m_gram_memory[m_grom_address | ((port-32)<<16)];
|
||||
m_module_bank = port - 16;
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: GRAM read access at %04x - switch to bank %d\n", tag(), offset & 0xffff, m_module_bank);
|
||||
if (TRACE_PORT) if (bNew) logerror("GRAM read access at %04x - switch to bank %d\n", offset & 0xffff, m_module_bank);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -412,11 +413,11 @@ void snug_high_speed_gpl_device::grom_readz(address_space& space, offs_t offset,
|
||||
{
|
||||
// *value = m_ram6_memory[m_grom_address];
|
||||
*value = m_ram6_memory[m_grom_address | ((port-48)<<16)];
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: RAM read access at %04x\n", tag(), offset & 0xffff);
|
||||
if (TRACE_PORT) if (bNew) logerror("RAM read access at %04x\n", offset & 0xffff);
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("%s: Attempt to read from undefined port 0x%0x; ignored.\n", tag(), port);
|
||||
logerror("Attempt to read from undefined port 0x%0x; ignored.\n", port);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -427,6 +428,7 @@ void snug_high_speed_gpl_device::grom_readz(address_space& space, offs_t offset,
|
||||
}
|
||||
// The address auto-increment should be done even when the card is
|
||||
// offline
|
||||
if (TRACE_ADDRESS) logerror("HSGPL GROM address %04x\n", m_grom_address);
|
||||
m_grom_address++;
|
||||
m_raddr_LSB = m_waddr_LSB = false;
|
||||
}
|
||||
@ -439,19 +441,19 @@ void snug_high_speed_gpl_device::cartspace_write(address_space& space, offs_t of
|
||||
{
|
||||
if (!m_card_enabled || m_flash_mode)
|
||||
{
|
||||
if (TRACE_IGNORE) logerror("%s: write ignored: card_enabled=%d, flash_mode=%d\n", tag(), m_card_enabled, m_flash_mode);
|
||||
if (TRACE_IGNORE) logerror("write ignored: card_enabled=%d, flash_mode=%d\n", m_card_enabled, m_flash_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TRACE_WRITE) logerror("%s: cartridge space write %04x <- %02x\n", tag(), offset, data);
|
||||
if (TRACE_WRITE) logerror("cartridge space write %04x <- %02x\n", offset, data);
|
||||
|
||||
if (!m_bank_inhibit && (m_module_bank < 16))
|
||||
{
|
||||
if ((offset & 1) == 0)
|
||||
{
|
||||
if ((offset & 0x9ff0)!=0) logerror("%s: unplausible ROM6 write: %04x <- %02x\n", tag(), offset, data);
|
||||
if ((offset & 0x9ff0)!=0) logerror("unplausible ROM6 write: %04x <- %02x\n", offset, data);
|
||||
m_current_bank = (offset>>1) & 3;
|
||||
if (TRACE_BANKING) logerror("%s: select bank %d\n", tag(), m_current_bank);
|
||||
if (TRACE_BANKING) logerror("select bank %d\n", m_current_bank);
|
||||
}
|
||||
return; /* right??? */
|
||||
}
|
||||
@ -459,7 +461,7 @@ void snug_high_speed_gpl_device::cartspace_write(address_space& space, offs_t of
|
||||
if ((m_mbx_enabled) && (offset==0x6ffe))
|
||||
{ /* MBX: mapper at 0x6ffe */
|
||||
m_current_bank = data & 0x03;
|
||||
if (TRACE_BANKING) logerror("%s: select bank MBX %d\n", tag(), m_current_bank);
|
||||
if (TRACE_BANKING) logerror("select bank MBX %d\n", m_current_bank);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -477,7 +479,7 @@ void snug_high_speed_gpl_device::cartspace_write(address_space& space, offs_t of
|
||||
// and !ram_enabled
|
||||
if (m_module_bank < 16)
|
||||
{
|
||||
logerror("%s: invalid write %04x <- %02x\n", tag(), offset, data);
|
||||
logerror("invalid write %04x <- %02x\n", offset, data);
|
||||
// feeprom is normally written to using GPL ports, and I don't know
|
||||
// whether writing through >6000 page is enabled
|
||||
/*
|
||||
@ -493,7 +495,7 @@ void snug_high_speed_gpl_device::cartspace_write(address_space& space, offs_t of
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("%s: unknown 0x6000 port\n", tag());
|
||||
logerror("unknown 0x6000 port\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -543,7 +545,7 @@ void snug_high_speed_gpl_device::grom_write(address_space& space, offs_t offset,
|
||||
{
|
||||
m_gram_memory[m_grom_address | (port<<16)] = data;
|
||||
m_module_bank = port + 16;
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: GRAM write access at %04x (GRMENA=1) - switch to bank %d\n", tag(), offset & 0xffff, port);
|
||||
if (TRACE_PORT) if (bNew) logerror("GRAM write access at %04x (GRMENA=1) - switch to bank %d\n", offset & 0xffff, port);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -551,7 +553,7 @@ void snug_high_speed_gpl_device::grom_write(address_space& space, offs_t offset,
|
||||
{
|
||||
m_grom_a_eeprom->write(space, m_grom_address | (port<<16), data, mem_mask);
|
||||
m_module_bank = port;
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: GROM write access at %04x - switch to bank %d\n", tag(), offset & 0xffff, port);
|
||||
if (TRACE_PORT) if (bNew) logerror("GROM write access at %04x - switch to bank %d\n", offset & 0xffff, port);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -559,21 +561,21 @@ void snug_high_speed_gpl_device::grom_write(address_space& space, offs_t offset,
|
||||
{
|
||||
m_grom_b_eeprom->write(space, m_grom_address | ((port-8)<<16), data, mem_mask);
|
||||
m_module_bank = port;
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: GROM write access at %04x - switch to bank %d\n", tag(), offset & 0xffff, port);
|
||||
if (TRACE_PORT) if (bNew) logerror("GROM write access at %04x - switch to bank %d\n", offset & 0xffff, port);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (port < 24)
|
||||
{
|
||||
m_dsr_eeprom->write(space, m_grom_address | ((port-16)<<16), data, mem_mask);
|
||||
if (TRACE_DSR) if (bNew) logerror("%s: write access to DSR bank %d-%d (%04x)\n", tag(), (port-16)<<3, ((port-16)<<3)+7, offset);
|
||||
if (TRACE_DSR) if (bNew) logerror("write access to DSR bank %d-%d (%04x)\n", (port-16)<<3, ((port-16)<<3)+7, offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (port < 32)
|
||||
{
|
||||
m_rom6_eeprom->write(space, m_grom_address | ((port-24)<<16), data, mem_mask);
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: ROM6 write access for module bank %d-%d (%04x)\n", tag(), (port-24)<<1, ((port-24)<<1)+1,offset & 0xffff);
|
||||
if (TRACE_PORT) if (bNew) logerror("ROM6 write access for module bank %d-%d (%04x)\n", (port-24)<<1, ((port-24)<<1)+1,offset & 0xffff);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -581,7 +583,7 @@ void snug_high_speed_gpl_device::grom_write(address_space& space, offs_t offset,
|
||||
{
|
||||
m_gram_memory[m_grom_address | ((port-32)<<16)] = data;
|
||||
m_module_bank = port - 16;
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: GRAM write access at %04x - switch to bank %d\n", tag(), offset & 0xffff, m_module_bank);
|
||||
if (TRACE_PORT) if (bNew) logerror("GRAM write access at %04x - switch to bank %d\n", offset & 0xffff, m_module_bank);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -589,11 +591,11 @@ void snug_high_speed_gpl_device::grom_write(address_space& space, offs_t offset,
|
||||
{
|
||||
// m_ram6_memory[m_grom_address] = data;
|
||||
m_ram6_memory[m_grom_address | ((port-48)<<16)] = data;
|
||||
if (TRACE_PORT) if (bNew) logerror("%s: RAM write access at %04x\n", tag(), offset & 0xffff);
|
||||
if (TRACE_PORT) if (bNew) logerror("RAM write access at %04x\n", offset & 0xffff);
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("%s: Attempt to write to undefined port; ignored.\n", tag());
|
||||
logerror("Attempt to write to undefined port; ignored.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -619,7 +621,7 @@ void snug_high_speed_gpl_device::device_start()
|
||||
|
||||
void snug_high_speed_gpl_device::device_reset()
|
||||
{
|
||||
logerror("%s: reset\n", tag());
|
||||
logerror("reset\n");
|
||||
m_dsr_enabled = false;
|
||||
m_gram_enabled = false;
|
||||
m_bank_inhibit = false;
|
||||
|
@ -220,7 +220,9 @@ peribox_device::peribox_device(const machine_config &mconfig, const char *tag, d
|
||||
: bus8z_device(mconfig, PERIBOX, "Peripheral expansion box", tag, owner, clock, "peribox", __FILE__),
|
||||
m_console_inta(*this),
|
||||
m_console_intb(*this),
|
||||
m_datamux_ready(*this), m_inta_flag(0), m_intb_flag(0), m_ready_flag(0)
|
||||
m_sgcpu_lcp(*this),
|
||||
m_datamux_ready(*this),
|
||||
m_inta_flag(0), m_intb_flag(0), m_lcp_flag(0), m_ready_flag(0)
|
||||
{
|
||||
for (int i=2; i <= 8; i++) m_slot[i] = nullptr;
|
||||
// The address prefix is actually created by the "Flex cable interface"
|
||||
@ -235,6 +237,7 @@ peribox_device::peribox_device(const machine_config &mconfig, device_type type,
|
||||
: bus8z_device(mconfig, type, name, tag, owner, clock, shortname, source),
|
||||
m_console_inta(*this),
|
||||
m_console_intb(*this),
|
||||
m_sgcpu_lcp(*this),
|
||||
m_datamux_ready(*this), m_inta_flag(0), m_intb_flag(0), m_ready_flag(0), m_address_prefix(0), m_msast(false), m_memen(false)
|
||||
{
|
||||
for (int i=2; i <= 8; i++) m_slot[i] = nullptr;
|
||||
@ -378,6 +381,17 @@ void peribox_device::intb_join(int slot, int state)
|
||||
m_console_intb((m_intb_flag != 0)? ASSERT_LINE : CLEAR_LINE);
|
||||
}
|
||||
|
||||
void peribox_device::lcp_join(int slot, int state)
|
||||
{
|
||||
if (TRACE_INT) logerror("%s: propagating LCP from slot %d to SGCPU: %d\n", tag(), slot, state);
|
||||
if (state==ASSERT_LINE)
|
||||
m_lcp_flag |= (1 << slot);
|
||||
else
|
||||
m_lcp_flag &= ~(1 << slot);
|
||||
|
||||
m_sgcpu_lcp((m_lcp_flag != 0)? ASSERT_LINE : CLEAR_LINE);
|
||||
}
|
||||
|
||||
/*
|
||||
When any device pulls down READY, READY goes down.
|
||||
*/
|
||||
@ -405,6 +419,7 @@ void peribox_device::device_start(void)
|
||||
// Resolve the callback lines to the console
|
||||
m_console_inta.resolve();
|
||||
m_console_intb.resolve();
|
||||
m_sgcpu_lcp.resolve();
|
||||
m_datamux_ready.resolve();
|
||||
|
||||
if (TRACE_EMU)
|
||||
@ -421,6 +436,7 @@ void peribox_device::device_config_complete()
|
||||
{
|
||||
m_inta_flag = 0;
|
||||
m_intb_flag = 0;
|
||||
m_lcp_flag = 0;
|
||||
m_ready_flag = 0;
|
||||
}
|
||||
|
||||
@ -721,6 +737,12 @@ WRITE_LINE_MEMBER( peribox_slot_device::set_intb )
|
||||
peb->intb_join(m_slotnumber, state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( peribox_slot_device::lcp_line )
|
||||
{
|
||||
peribox_device *peb = static_cast<peribox_device*>(owner());
|
||||
peb->lcp_join(m_slotnumber, state);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( peribox_slot_device::set_ready )
|
||||
{
|
||||
peribox_device *peb = static_cast<peribox_device*>(owner());
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
template<class _Object> static devcb_base &static_set_inta_callback(device_t &device, _Object object) { return downcast<peribox_device &>(device).m_console_inta.set_callback(object); }
|
||||
template<class _Object> static devcb_base &static_set_intb_callback(device_t &device, _Object object) { return downcast<peribox_device &>(device).m_console_intb.set_callback(object); }
|
||||
template<class _Object> static devcb_base &static_set_ready_callback(device_t &device, _Object object) { return downcast<peribox_device &>(device).m_datamux_ready.set_callback(object); }
|
||||
template<class _Object> static devcb_base &static_set_lcp_callback(device_t &device, _Object object) { return downcast<peribox_device &>(device).m_sgcpu_lcp.set_callback(object); }
|
||||
|
||||
// Next eight methods are called from the console
|
||||
DECLARE_READ8Z_MEMBER(readz) override;
|
||||
@ -74,6 +75,7 @@ protected:
|
||||
// Next three methods call back the console
|
||||
devcb_write_line m_console_inta; // INTA line (Box to console)
|
||||
devcb_write_line m_console_intb; // INTB line
|
||||
devcb_write_line m_sgcpu_lcp; // For EVPC with SGCPU only
|
||||
devcb_write_line m_datamux_ready; // READY line (to the datamux)
|
||||
|
||||
void set_slot_loaded(int slot, peribox_slot_device* slotdev);
|
||||
@ -83,10 +85,12 @@ protected:
|
||||
// if any one slot asserts the line, the joint line is asserted.
|
||||
void inta_join(int slot, int state);
|
||||
void intb_join(int slot, int state);
|
||||
void lcp_join(int slot, int state);
|
||||
void ready_join(int slot, int state);
|
||||
|
||||
int m_inta_flag;
|
||||
int m_intb_flag;
|
||||
int m_lcp_flag;
|
||||
int m_ready_flag;
|
||||
|
||||
// The TI-99/4(A) Flex Cable Interface (slot 1) pulls up the AMA/AMB/AMC lines to 1/1/1.
|
||||
@ -173,6 +177,7 @@ public:
|
||||
// Called from the card (direction to box)
|
||||
DECLARE_WRITE_LINE_MEMBER( set_inta );
|
||||
DECLARE_WRITE_LINE_MEMBER( set_intb );
|
||||
DECLARE_WRITE_LINE_MEMBER( lcp_line );
|
||||
DECLARE_WRITE_LINE_MEMBER( set_ready );
|
||||
|
||||
DECLARE_READ8Z_MEMBER(crureadz);
|
||||
@ -257,4 +262,7 @@ protected:
|
||||
#define MCFG_PERIBOX_READY_HANDLER( _ready ) \
|
||||
devcb = &peribox_device::static_set_ready_callback( *device, DEVCB_##_ready );
|
||||
|
||||
#define MCFG_PERIBOX_LCP_HANDLER( _lcp ) \
|
||||
devcb = &peribox_device::static_set_lcp_callback( *device, DEVCB_##_lcp );
|
||||
|
||||
#endif /* __PBOX__ */
|
||||
|
@ -11,22 +11,26 @@
|
||||
addresses at 4000, 4002, ..., 401e, which correspond to memory locations
|
||||
0000-0fff, 1000-1fff, ..., f000-ffff.
|
||||
|
||||
Michael Zapf
|
||||
According to a software distribution disk from the South West 99ers group,
|
||||
the predecessor of this card was the Asgard Expanded Memory System (AEMS).
|
||||
Although some documentation and software was available for it, it was never
|
||||
built. Instead, a simpler memory card called the Asgard Memory System (AMS)
|
||||
was built. The South West 99ers group built a better version of this card
|
||||
called the Super AMS. Any documentation and software containing a reference
|
||||
to the AEMS are applicable to either AMS or SAMS.
|
||||
|
||||
February 2012: Rewritten as class
|
||||
Michael Zapf
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include "samsmem.h"
|
||||
#define RAMREGION "ram"
|
||||
|
||||
#define SAMS_CRU_BASE 0x1e00
|
||||
|
||||
#define VERBOSE 1
|
||||
#define LOG logerror
|
||||
|
||||
sams_memory_expansion_device::sams_memory_expansion_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: ti_expansion_card_device(mconfig, TI99_SAMSMEM, "SuperAMS memory expansion card", tag, owner, clock, "ti99_sams", __FILE__), m_ram(nullptr), m_map_mode(false), m_access_mapper(false)
|
||||
: ti_expansion_card_device(mconfig, TI99_SAMSMEM, "SuperAMS memory expansion card", tag, owner, clock, "ti99_sams", __FILE__),
|
||||
m_ram(*this, RAM_TAG),
|
||||
m_map_mode(false), m_access_mapper(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -49,12 +53,12 @@ READ8Z_MEMBER(sams_memory_expansion_device::readz)
|
||||
if (!m_map_mode)
|
||||
{
|
||||
// transparent mode
|
||||
*value = m_ram[offset & 0xffff];
|
||||
*value = m_ram->pointer()[offset & 0xffff];
|
||||
}
|
||||
else
|
||||
{
|
||||
base = (m_mapper[(offset & 0xf000)>>12] << 12);
|
||||
*value = m_ram[base | (offset & 0x0fff)];
|
||||
*value = m_ram->pointer()[base | (offset & 0x0fff)];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -73,12 +77,12 @@ WRITE8_MEMBER(sams_memory_expansion_device::write)
|
||||
if (!m_map_mode)
|
||||
{
|
||||
// transparent mode
|
||||
m_ram[offset & 0xffff] = data;
|
||||
m_ram->pointer()[offset & 0xffff] = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
base = (m_mapper[(offset & 0xf000)>>12] << 12);
|
||||
m_ram[base | (offset & 0x0fff)] = data;
|
||||
m_ram->pointer()[base | (offset & 0x0fff)] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -97,37 +101,31 @@ WRITE8_MEMBER(sams_memory_expansion_device::cruwrite)
|
||||
{
|
||||
if ((offset & 0xff00)==SAMS_CRU_BASE)
|
||||
{
|
||||
if (VERBOSE>7) LOG("cru address %04x = %02x\n", offset&0xffff, data);
|
||||
|
||||
if ((offset & 0x000e)==0) m_access_mapper = (data!=0);
|
||||
if ((offset & 0x000e)==2) m_map_mode = (data!=0);
|
||||
}
|
||||
}
|
||||
|
||||
MACHINE_CONFIG_FRAGMENT( sams_mem )
|
||||
MCFG_RAM_ADD(RAM_TAG)
|
||||
MCFG_RAM_DEFAULT_SIZE("1M")
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
ROM_START( sams_card )
|
||||
ROM_REGION(0x100000, RAMREGION, 0)
|
||||
ROM_FILL(0x0000, 0x100000, 0x00)
|
||||
ROM_END
|
||||
machine_config_constructor sams_memory_expansion_device::device_mconfig_additions() const
|
||||
{
|
||||
return MACHINE_CONFIG_NAME( sams_mem );
|
||||
}
|
||||
|
||||
void sams_memory_expansion_device::device_start()
|
||||
{
|
||||
if (VERBOSE>5) LOG("SuperAMS: start\n");
|
||||
m_ram = memregion(RAMREGION)->base();
|
||||
}
|
||||
|
||||
void sams_memory_expansion_device::device_reset()
|
||||
{
|
||||
if (VERBOSE>5) LOG("SuperAMS: reset\n");
|
||||
// Resetting values
|
||||
m_map_mode = false;
|
||||
m_access_mapper = false;
|
||||
for (auto & elem : m_mapper) elem = 0;
|
||||
}
|
||||
|
||||
const rom_entry *sams_memory_expansion_device::device_rom_region() const
|
||||
{
|
||||
return ROM_NAME( sams_card );
|
||||
}
|
||||
|
||||
const device_type TI99_SAMSMEM = &device_creator<sams_memory_expansion_device>;
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "emu.h"
|
||||
#include "peribox.h"
|
||||
#include "machine/ram.h"
|
||||
|
||||
extern const device_type TI99_SAMSMEM;
|
||||
|
||||
@ -30,13 +31,15 @@ public:
|
||||
DECLARE_READ8Z_MEMBER(crureadz) override;
|
||||
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
||||
|
||||
machine_config_constructor device_mconfig_additions() const override;
|
||||
|
||||
protected:
|
||||
virtual void device_start(void) override;
|
||||
virtual void device_reset(void) override;
|
||||
virtual const rom_entry *device_rom_region(void) const override;
|
||||
void device_start(void) override;
|
||||
void device_reset(void) override;
|
||||
|
||||
private:
|
||||
UINT8* m_ram;
|
||||
// Console RAM
|
||||
required_device<ram_device> m_ram;
|
||||
int m_mapper[16];
|
||||
bool m_map_mode;
|
||||
bool m_access_mapper;
|
||||
|
@ -124,7 +124,18 @@ void ti99_datamux_device::read_all(address_space& space, UINT16 addr, UINT8 *val
|
||||
// Video
|
||||
if ((addr & 0xf801)==0x8800)
|
||||
{
|
||||
m_video->readz(space, addr, value);
|
||||
// Forward to VDP unless we have an EVPC
|
||||
if (m_video != nullptr)
|
||||
{
|
||||
if ((addr & 2) != 0)
|
||||
{ // read VDP status
|
||||
*value = m_video->register_read(space, 0);
|
||||
}
|
||||
else
|
||||
{ // read VDP RAM
|
||||
*value = m_video->vram_read(space, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,12 +163,28 @@ void ti99_datamux_device::write_all(address_space& space, UINT16 addr, UINT8 val
|
||||
|
||||
// Cartridge port and sound
|
||||
if ((addr & 0xe000)==0x6000) m_gromport->write(space, addr, value);
|
||||
if ((addr & 0xfc01)==0x8400) m_sound->write(space, 0, value);
|
||||
|
||||
// Only if the sound chip has not been removed
|
||||
if ((addr & 0xfc01)==0x8400)
|
||||
{
|
||||
if (m_sound != nullptr) m_sound->write(space, 0, value);
|
||||
}
|
||||
|
||||
// Video
|
||||
if ((addr & 0xf801)==0x8800)
|
||||
{
|
||||
m_video->write(space, addr, value);
|
||||
// Forward to VDP unless we have an EVPC
|
||||
if (m_video != nullptr)
|
||||
{
|
||||
if ((addr & 2) != 0)
|
||||
{ // write VDP address/register
|
||||
m_video->register_write(space, 0, value);
|
||||
}
|
||||
else
|
||||
{ // write VDP data
|
||||
m_video->vram_write(space, 0, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PEB gets all accesses
|
||||
@ -560,7 +587,7 @@ void ti99_datamux_device::device_reset(void)
|
||||
|
||||
void ti99_datamux_device::device_config_complete()
|
||||
{
|
||||
m_video = downcast<bus8z_device*>(owner()->subdevice(VIDEO_SYSTEM_TAG));
|
||||
m_video = downcast<tms9928a_device*>(owner()->subdevice(VDP_TAG));
|
||||
m_sound = downcast<sn76496_base_device*>(owner()->subdevice(TISOUNDCHIP_TAG));
|
||||
m_gromport = downcast<gromport_device*>(owner()->subdevice(GROMPORT_TAG));
|
||||
m_peb = downcast<peribox_device*>(owner()->subdevice(PERIBOX_TAG));
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "bus/ti99_peb/peribox.h"
|
||||
#include "sound/sn76496.h"
|
||||
#include "video/tms9928a.h"
|
||||
#include "bus/ti99x/videowrp.h"
|
||||
|
||||
extern const device_type DATAMUX;
|
||||
|
||||
@ -56,7 +55,7 @@ protected:
|
||||
|
||||
private:
|
||||
// Link to the video processor
|
||||
bus8z_device* m_video;
|
||||
tms9928a_device* m_video;
|
||||
|
||||
// Link to the sound processor
|
||||
sn76496_base_device* m_sound;
|
||||
|
@ -18,7 +18,6 @@
|
||||
#define TMS9901_TAG "tms9901"
|
||||
#define TIBOARD_TAG "ti_board"
|
||||
#define DATAMUX_TAG "datamux_16_8"
|
||||
#define VIDEO_SYSTEM_TAG "video"
|
||||
#define SCREEN_TAG "screen"
|
||||
#define TISOUNDCHIP_TAG "soundchip"
|
||||
#define TISOUND_TAG "tisound"
|
||||
@ -31,6 +30,8 @@
|
||||
#define HANDSET_TAG "handset"
|
||||
#define JOYPORT_TAG "joyport"
|
||||
#define VDP_TAG "vdp"
|
||||
#define EVPC_CONN_TAG "evpc_conn"
|
||||
|
||||
#define DSRROM "dsrrom"
|
||||
#define CONSOLEROM "consolerom"
|
||||
|
||||
@ -137,6 +138,42 @@ public:
|
||||
virtual DECLARE_SETADDRESS_DBIN_MEMBER( setaddress_dbin ) { };
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
Connector from EVPC
|
||||
We need this for the TI-99/4A console as well as for the SGCPU, so we have
|
||||
to use callbacks
|
||||
****************************************************************************/
|
||||
class ti99_4x_state;
|
||||
|
||||
class evpc_clock_connector;
|
||||
|
||||
const device_type EVPC_CONN = &device_creator<evpc_clock_connector>;
|
||||
|
||||
class evpc_clock_connector : public device_t
|
||||
{
|
||||
public:
|
||||
evpc_clock_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, EVPC_CONN, "EVPC clock connector", tag, owner, clock, "ti99_evpc_clock", __FILE__),
|
||||
m_vdpint(*this) { };
|
||||
|
||||
template<class _Object> static devcb_base &static_set_vdpint_callback(device_t &device, _Object object)
|
||||
{
|
||||
return downcast<evpc_clock_connector &>(device).m_vdpint.set_callback(object);
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( vclock_line ) { m_vdpint(state); }
|
||||
void device_start() override { m_vdpint.resolve(); }
|
||||
|
||||
private:
|
||||
// VDPINT line to the CPU
|
||||
devcb_write_line m_vdpint;
|
||||
};
|
||||
|
||||
|
||||
#define MCFG_ADD_EVPC_CONNECTOR( _tag, _vdpint ) \
|
||||
MCFG_DEVICE_ADD(_tag, EVPC_CONN, 0) \
|
||||
devcb = &evpc_clock_connector::static_set_vdpint_callback( *device, DEVCB_##_vdpint );
|
||||
|
||||
/****************************************************************************
|
||||
Constants
|
||||
****************************************************************************/
|
||||
|
@ -1,121 +0,0 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Michael Zapf
|
||||
/****************************************************************************
|
||||
|
||||
TI-99/4A Video subsystem
|
||||
This device actually wraps the naked video chip implementation
|
||||
|
||||
EVPC (Enhanced Video Processor Card) from SNUG
|
||||
based on v9938 (may also be equipped with v9958)
|
||||
Can be used with TI-99/4A as an add-on card; internal VDP must be removed
|
||||
|
||||
The SGCPU ("TI-99/4P") only runs with EVPC
|
||||
|
||||
Michael Zapf
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "videowrp.h"
|
||||
|
||||
/*
|
||||
Constructors
|
||||
*/
|
||||
ti_video_device::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)
|
||||
: bus8z_device(mconfig, type, name, tag, owner, clock, shortname, source),
|
||||
m_tms9928a(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ti_std_video_device::ti_std_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: ti_video_device(mconfig, TI99VIDEO, "TI99 STD Video subsystem", tag, owner, clock, "ti99_video", __FILE__)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
Accessing TMS9928A (TI-99/4A)
|
||||
*/
|
||||
READ8Z_MEMBER( ti_std_video_device::readz )
|
||||
{
|
||||
if (space.debugger_access()) return;
|
||||
|
||||
if (offset & 2)
|
||||
{ /* read VDP status */
|
||||
*value = m_tms9928a->register_read(space, 0);
|
||||
}
|
||||
else
|
||||
{ /* read VDP RAM */
|
||||
*value = m_tms9928a->vram_read(space, 0);
|
||||
}
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( ti_std_video_device::write )
|
||||
{
|
||||
if (space.debugger_access()) return;
|
||||
|
||||
if (offset & 2)
|
||||
{ /* write VDP address */
|
||||
m_tms9928a->register_write(space, 0, data);
|
||||
}
|
||||
else
|
||||
{ /* write VDP data */
|
||||
m_tms9928a->vram_write(space, 0, data);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
Accessing v9938 via 16 bit bus (SGCPU)
|
||||
*/
|
||||
READ16_MEMBER( ti_exp_video_device::read16 )
|
||||
{
|
||||
if (space.debugger_access()) return 0;
|
||||
return (int)(m_v9938->read(space, offset)<<8);
|
||||
}
|
||||
|
||||
WRITE16_MEMBER( ti_exp_video_device::write16 )
|
||||
{
|
||||
if (space.debugger_access()) return;
|
||||
m_v9938->write(space, offset, (data>>8)&0xff);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/*
|
||||
Accessing v9938 via 8 bit bus (EVPC)
|
||||
*/
|
||||
READ8Z_MEMBER( ti_exp_video_device::readz )
|
||||
{
|
||||
if (space.debugger_access()) return;
|
||||
*value = m_v9938->read(space, offset>>1);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( ti_exp_video_device::write )
|
||||
{
|
||||
if (space.debugger_access()) return;
|
||||
m_v9938->write(space, offset>>1, data);
|
||||
}
|
||||
|
||||
void ti_video_device::device_start(void)
|
||||
{
|
||||
m_tms9928a = static_cast<tms9928a_device*>(machine().device(VDP_TAG));
|
||||
}
|
||||
|
||||
void ti_exp_video_device::device_start(void)
|
||||
{
|
||||
m_v9938 = static_cast<v9938_device*>(machine().device(VDP_TAG));
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
|
||||
const device_type TI99VIDEO = &device_creator<ti_std_video_device>;
|
||||
const device_type V9938VIDEO = &device_creator<ti_exp_video_device>;
|
@ -1,93 +0,0 @@
|
||||
// license:LGPL-2.1+
|
||||
// copyright-holders:Michael Zapf
|
||||
/****************************************************************************
|
||||
|
||||
TI-99/4A / EVPC Video subsystem
|
||||
See videowrp.c for documentation
|
||||
|
||||
Michael Zapf
|
||||
October 2010
|
||||
January 2012: Rewritten as class
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef __TIVIDEO__
|
||||
#define __TIVIDEO__
|
||||
|
||||
#include "video/tms9928a.h"
|
||||
#include "video/v9938.h"
|
||||
#include "ti99defs.h"
|
||||
|
||||
class ti_video_device : public bus8z_device
|
||||
{
|
||||
public:
|
||||
virtual void reset_vdp(int state) =0;
|
||||
|
||||
protected:
|
||||
tms9928a_device *m_tms9928a;
|
||||
|
||||
/* 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 DECLARE_READ8Z_MEMBER(readz) override { };
|
||||
virtual DECLARE_WRITE8_MEMBER(write) override { };
|
||||
};
|
||||
|
||||
/*
|
||||
Used in the TI-99/4A and TI-99/8
|
||||
*/
|
||||
class ti_std_video_device : public ti_video_device
|
||||
{
|
||||
public:
|
||||
ti_std_video_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
DECLARE_READ8Z_MEMBER(readz) override;
|
||||
DECLARE_WRITE8_MEMBER(write) override;
|
||||
void reset_vdp(int state) override { m_tms9928a->reset_line(state); }
|
||||
};
|
||||
|
||||
/*
|
||||
Used in the EVPC
|
||||
*/
|
||||
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);
|
||||
DECLARE_READ8Z_MEMBER(readz) override;
|
||||
DECLARE_WRITE8_MEMBER(write) override;
|
||||
DECLARE_READ16_MEMBER(read16);
|
||||
DECLARE_WRITE16_MEMBER(write16);
|
||||
void reset_vdp(int state) override { m_v9938->reset_line(state); }
|
||||
|
||||
protected:
|
||||
virtual void device_start(void) override;
|
||||
|
||||
private:
|
||||
v9938_device *m_v9938;
|
||||
};
|
||||
|
||||
extern const device_type TI99VIDEO;
|
||||
extern const device_type V9938VIDEO;
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
#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, _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 )
|
||||
|
||||
#endif /* __TIVIDEO__ */
|
@ -2,53 +2,126 @@
|
||||
// copyright-holders:Michael Zapf
|
||||
/****************************************************************************
|
||||
|
||||
SNUG SGCPU (a.k.a. 99/4p) system
|
||||
SNUG Second Generation CPU (SGCPU, aka TI-99/4P)
|
||||
|
||||
This system is a reimplementation of the old ti99/4a console. It is known
|
||||
both as the 99/4p ("peripheral box", since the system is a card to be
|
||||
inserted in the peripheral box, instead of a self contained console), and
|
||||
as the SGCPU ("Second Generation CPU", which was originally the name used
|
||||
in TI documentation to refer to either (or both) TI99/5 and TI99/8
|
||||
projects).
|
||||
This system is known both as the TI-99/4P ("Peripheral box", since the
|
||||
system is a card to be inserted in the peripheral box, instead of a
|
||||
self-contained console), and as the SGCPU ("Second Generation CPU",
|
||||
which was originally the name used in TI documentation to refer to either
|
||||
(or both) TI-99/5 and TI-99/8 projects).
|
||||
|
||||
The SGCPU was designed and built by the SNUG (System 99 Users Group),
|
||||
namely by Michael Becker for the hardware part and Harald Glaab for the
|
||||
software part. It has no relationship with TI.
|
||||
|
||||
The card is architectured around a 16-bit bus (vs. an 8-bit bus in every
|
||||
other TI99 system). It includes 64kb of ROM, including a GPL interpreter,
|
||||
an internal DSR ROM which contains system-specific code, part of the TI
|
||||
extended Basic interpreter, and up to 1Mbyte of RAM. It still includes a
|
||||
16-bit to 8-bit multiplexer in order to support extension cards designed
|
||||
for TI99/4a, but it can support 16-bit cards, too. It does not include
|
||||
GROMs, video or sound: instead, it relies on the HSGPL and EVPC cards to
|
||||
do the job.
|
||||
The card is a complete redesign of the original TI-99/4A mainboard to fit
|
||||
on a peripheral card, thus replacing the console. It shows no original
|
||||
circuits on its board; the concept is to cannibalize a TI-99/4A console,
|
||||
moving its main circuits (TMS9900, TMS9901) into the sockets on this board.
|
||||
|
||||
IMPORTANT: The SGCPU card relies on a properly set up HSGPL flash memory
|
||||
card; without, it will immediately lock up. It is impossible to set it up
|
||||
from here (a bootstrap problem; you cannot start without the HSGPL).
|
||||
The best chance is to start a ti99_4ev with a plugged-in HSGPL
|
||||
and go through the setup process there. Copy the nvram files of the hsgpl into this
|
||||
driver's nvram subdirectory. The contents will be directly usable for the SGCPU.
|
||||
The sound chip is not plugged on the SGCPU but on the EVPC card which
|
||||
provides the video processor for SGCPU card (see below).
|
||||
|
||||
The card offers a PC-style keyboard interface which adapts the keyboard
|
||||
to the matrix organisation expected by the operating system of the TI.
|
||||
|
||||
All decoding and further features are implemented by a MACH chip, which
|
||||
appears on many SNUG cards.
|
||||
|
||||
On the card, most circuits are directly accessed by a 16-bit data bus,
|
||||
which ensures a significant speed-up compared to the original console. Only
|
||||
when accessing external devices via the PEB, a databus multiplexer comes into
|
||||
play which is implemented in the same way as the one in the original console,
|
||||
also contained in the MACH.
|
||||
|
||||
The SGCPU offers a special connector at the back, containing the remaining
|
||||
8 data bus lines; by this feature, expansion cards can be connected at
|
||||
full 16 bit width. Only the HRD16 card (not yet emulated), which is a
|
||||
RAMDisk card, actually uses it.
|
||||
|
||||
EPROM layout 64K
|
||||
----------------
|
||||
The memory region is shifted by 4000 in the EPROM address space
|
||||
According to the designers, this is caused by the next-to most significant
|
||||
address line (2^14) being locked to 1. This is done to allow for smaller
|
||||
24pin EPROM to be used.
|
||||
|
||||
Area EPROM offset Mapped at
|
||||
---------------------------------------
|
||||
ROM0 4000 (0100) 0000
|
||||
DSR C000 (1100) 4000
|
||||
ROM6A 6000 (0110) 6000
|
||||
ROM6B E000 (1110) 6000
|
||||
|
||||
System ROM
|
||||
----------
|
||||
The GPL interpreter is located in the EPROM as ROM0 (see above). The
|
||||
SGCPU does not contain any GROM, which contain the actual TI operating
|
||||
system and the BASIC interpreter. The GROMs are replaced by the HSGPL card.
|
||||
|
||||
==== CAUTION ====: This means that the HSGPL must be properly set up before
|
||||
starting up the SGCPU. Otherwise, the emulation locks up immediately with a
|
||||
BLACK SCREEN.
|
||||
|
||||
In the real environment, the HSGPL has usually been set up on delivery.
|
||||
In MESS we have to create a suitable HSGPL memory content. Best practice
|
||||
is to start the TI-99/4A console with EVPC support (driver ti99_4ev) with
|
||||
a plugged-in HSGPL and to go through the setup process there.
|
||||
Finally, the nvram files of the HSGPL must be copied into this driver's nvram
|
||||
subdirectory. The contents will be directly usable for the SGCPU.
|
||||
|
||||
RAM: AEMS emulation
|
||||
--------------------
|
||||
The Asgard Expanded Memory System is a peripheral card whose successor
|
||||
(Super AMS) is available in MESS. The AEMS card is emulated inside the MACH
|
||||
chip of the SGCPU. For more information see samsmem.cpp.
|
||||
|
||||
The first four address lines are used to select one of 16 mapper values with
|
||||
8 bits each. Instead of these first 4 lines, the 8 bits are prepended to
|
||||
the remaining address, yielding a 20 bit address space.
|
||||
|
||||
The mapper values are mapped into the address space at 4000 by setting
|
||||
CRU bit 1E00. Only the even addresses are used, so the first mapper byte is
|
||||
at 4000, the second at 4002, the last one at 401E.
|
||||
|
||||
The mapping mode can be turned on and off by the CRU bit at address 1E02.
|
||||
When turned off, the address is passed through to the RAM circuits.
|
||||
|
||||
Since the only RAM areas on the TI systems are at 2000-3FFF and A000-FFFF,
|
||||
the typical usage is to use the AEMS as a 32K expansion in unmapped mode
|
||||
(the remaining 32K of the address space is decoded earlier, and does not
|
||||
affect the card), and to use it as paged memory in the 2000-3FFF and A000-FFFF
|
||||
areas by setting the mapper appropriately. Mapper registers referring to
|
||||
other memory areas have no effect.
|
||||
|
||||
Video and sound
|
||||
---------------
|
||||
The SGCPU relies on the EVPC or EVPC2 card to provide video capabilities.
|
||||
This card (rel.1) is emulated in MESS and is based on the v9938 video
|
||||
display processor.
|
||||
In order to route the VDP interrupt to the SGCPU card, the previously
|
||||
unused LCP* line in the Peripheral Expansion Box is used.
|
||||
|
||||
The sound chip requires the video clock, and therefore it is moved from the
|
||||
console to the EVPC card.
|
||||
|
||||
Joystick and cassette
|
||||
---------------------
|
||||
The card features a 25-pin connector at the back which contains the lines
|
||||
for the joysticks and one cassette input/output. An adapter must be built
|
||||
to be able to use the common cables.
|
||||
|
||||
Michael Zapf
|
||||
|
||||
February 2012: Rewritten as class
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "cpu/tms9900/tms9900.h"
|
||||
#include "sound/wave.h"
|
||||
#include "sound/dac.h"
|
||||
#include "sound/sn76496.h"
|
||||
|
||||
#include "machine/tms9901.h"
|
||||
#include "imagedev/cassette.h"
|
||||
|
||||
#include "bus/ti99x/videowrp.h"
|
||||
#include "bus/ti99x/joyport.h"
|
||||
|
||||
#include "bus/ti99_peb/peribox.h"
|
||||
|
||||
#define TMS9901_TAG "tms9901"
|
||||
@ -57,6 +130,9 @@
|
||||
#define TRACE_ILLWRITE 0
|
||||
#define TRACE_READY 0
|
||||
#define TRACE_INT 0
|
||||
#define TRACE_ADDRESS 0
|
||||
#define TRACE_MEM 0
|
||||
#define TRACE_MUX 0
|
||||
|
||||
class ti99_4p_state : public driver_device
|
||||
{
|
||||
@ -65,28 +141,28 @@ public:
|
||||
: driver_device(mconfig, type, tag),
|
||||
m_cpu(*this, "maincpu"),
|
||||
m_tms9901(*this, TMS9901_TAG),
|
||||
m_sound(*this, TISOUNDCHIP_TAG),
|
||||
m_video(*this, VIDEO_SYSTEM_TAG),
|
||||
m_cassette(*this, "cassette"),
|
||||
m_peribox(*this, PERIBOX_TAG),
|
||||
m_joyport(*this, JOYPORT_TAG) { }
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( console_ready );
|
||||
DECLARE_WRITE_LINE_MEMBER( console_ready_dmux );
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( ready_line );
|
||||
DECLARE_WRITE_LINE_MEMBER( extint );
|
||||
DECLARE_WRITE_LINE_MEMBER( notconnected );
|
||||
DECLARE_READ8_MEMBER( interrupt_level );
|
||||
|
||||
DECLARE_SETOFFSET_MEMBER( setoffset );
|
||||
DECLARE_READ16_MEMBER( memread );
|
||||
DECLARE_WRITE16_MEMBER( memwrite );
|
||||
DECLARE_WRITE_LINE_MEMBER( dbin_in );
|
||||
|
||||
DECLARE_READ16_MEMBER( samsmem_read );
|
||||
DECLARE_WRITE16_MEMBER( samsmem_write );
|
||||
|
||||
DECLARE_WRITE8_MEMBER(external_operation);
|
||||
DECLARE_WRITE_LINE_MEMBER( clock_out );
|
||||
DECLARE_WRITE_LINE_MEMBER( dbin_line );
|
||||
|
||||
void clock_in(int clock);
|
||||
void datamux_clock_in(int clock);
|
||||
|
||||
// CRU (Communication Register Unit) handling
|
||||
DECLARE_READ8_MEMBER( cruread );
|
||||
@ -103,12 +179,10 @@ public:
|
||||
virtual void machine_start() override;
|
||||
DECLARE_MACHINE_RESET(ti99_4p);
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(set_tms9901_INT2_from_v9938);
|
||||
DECLARE_WRITE_LINE_MEMBER(video_interrupt_in);
|
||||
|
||||
required_device<tms9900_device> m_cpu;
|
||||
required_device<tms9901_device> m_tms9901;
|
||||
required_device<sn76496_base_device> m_sound;
|
||||
required_device<ti_exp_video_device> m_video;
|
||||
required_device<cassette_image_device> m_cassette;
|
||||
required_device<peribox_device> m_peribox;
|
||||
required_device<joyport_device> m_joyport;
|
||||
@ -116,15 +190,6 @@ public:
|
||||
// Pointer to ROM0
|
||||
UINT16 *m_rom0;
|
||||
|
||||
// Pointer to DSR ROM
|
||||
UINT16 *m_dsr;
|
||||
|
||||
// Pointer to ROM6, first bank
|
||||
UINT16 *m_rom6a;
|
||||
|
||||
// Pointer to ROM6, second bank
|
||||
UINT16 *m_rom6b;
|
||||
|
||||
// AMS RAM (1 Mib)
|
||||
std::vector<UINT16> m_ram;
|
||||
|
||||
@ -134,12 +199,14 @@ public:
|
||||
// First joystick. 6 for TI-99/4A
|
||||
int m_firstjoy;
|
||||
|
||||
// READY line
|
||||
int m_ready_line, m_ready_line_dmux;
|
||||
|
||||
private:
|
||||
DECLARE_READ16_MEMBER( datamux_read );
|
||||
DECLARE_WRITE16_MEMBER( datamux_write );
|
||||
|
||||
int decode_address(int address);
|
||||
DECLARE_READ16_MEMBER( debugger_read );
|
||||
DECLARE_WRITE16_MEMBER( debugger_write );
|
||||
|
||||
void ready_join();
|
||||
|
||||
void set_keyboard_column(int number, int data);
|
||||
|
||||
int m_keyboard_column;
|
||||
@ -163,6 +230,36 @@ private:
|
||||
// TRUE when mapper registers are accessible
|
||||
bool m_access_mapper;
|
||||
|
||||
// Value on address bus (after being set by setaddress)
|
||||
int m_addr_buf;
|
||||
|
||||
// Address decoding result
|
||||
int m_decode;
|
||||
|
||||
// Ready state of the databus multiplexer
|
||||
bool m_muxready;
|
||||
|
||||
// Incoming Ready level
|
||||
line_state m_sysready;
|
||||
|
||||
// Saves a pointer to the address space
|
||||
address_space* m_spacep;
|
||||
|
||||
// Internal DSR mapped in
|
||||
bool m_internal_dsr_active;
|
||||
|
||||
// Mapper visible in 4000 area
|
||||
bool m_mapper_active;
|
||||
|
||||
// ROM6 visible in 6000
|
||||
bool m_rom6_active;
|
||||
|
||||
// Upper bank of ROM6 selected
|
||||
bool m_rom6_upper;
|
||||
|
||||
// State of the DBIN line
|
||||
line_state m_dbin;
|
||||
|
||||
UINT8 m_lowbyte;
|
||||
UINT8 m_highbyte;
|
||||
UINT8 m_latch;
|
||||
@ -170,6 +267,9 @@ private:
|
||||
// Mapper registers
|
||||
UINT8 m_mapper[16];
|
||||
|
||||
// Pointer to EPROM
|
||||
UINT16 *m_rom;
|
||||
|
||||
// Latch for 9901 INT2, INT1 lines
|
||||
int m_9901_int;
|
||||
void set_9901_int(int line, line_state state);
|
||||
@ -178,8 +278,16 @@ private:
|
||||
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ROM0BASE = 0x4000,
|
||||
DSRBASE = 0xc000,
|
||||
ROM6LBASE = 0x6000,
|
||||
ROM6UBASE = 0xe000
|
||||
};
|
||||
|
||||
static ADDRESS_MAP_START(memmap, AS_PROGRAM, 16, ti99_4p_state)
|
||||
AM_RANGE(0x0000, 0xffff) AM_READWRITE( memread, memwrite )
|
||||
AM_RANGE(0x0000, 0xffff) AM_READWRITE( memread, memwrite ) AM_SETOFFSET( setoffset )
|
||||
ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START(cru_map, AS_IO, 8, ti99_4p_state)
|
||||
@ -267,226 +375,309 @@ static INPUT_PORTS_START(ti99_4p)
|
||||
|
||||
INPUT_PORTS_END
|
||||
|
||||
enum
|
||||
{
|
||||
SGCPU_NONE = 0,
|
||||
SGCPU_SYSROM,
|
||||
SGCPU_RAM,
|
||||
SGCPU_INTDSR,
|
||||
SGCPU_MAPPER,
|
||||
SGCPU_ROM6,
|
||||
SGCPU_PADRAM,
|
||||
SGCPU_PEB
|
||||
};
|
||||
|
||||
int ti99_4p_state::decode_address(int address)
|
||||
{
|
||||
int dec = SGCPU_NONE;
|
||||
switch (address & 0xe000)
|
||||
{
|
||||
case 0x0000:
|
||||
dec = SGCPU_SYSROM;
|
||||
break;
|
||||
case 0x2000:
|
||||
case 0xa000:
|
||||
case 0xc000:
|
||||
case 0xe000:
|
||||
dec = SGCPU_RAM;
|
||||
break;
|
||||
case 0x4000:
|
||||
if (m_internal_dsr_active) dec = SGCPU_INTDSR;
|
||||
else if (m_mapper_active) dec = SGCPU_MAPPER;
|
||||
break;
|
||||
case 0x6000:
|
||||
if (m_rom6_active) dec = SGCPU_ROM6;
|
||||
break;
|
||||
case 0x8000:
|
||||
if ((m_addr_buf & 0x1c00)==0x0000) dec = SGCPU_PADRAM;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return dec;
|
||||
}
|
||||
|
||||
/*
|
||||
Memory access
|
||||
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_4p_state::setoffset )
|
||||
{
|
||||
m_addr_buf = offset << 1;
|
||||
m_waitcount = 0;
|
||||
|
||||
if (TRACE_ADDRESS) logerror("set address %04x\n", m_addr_buf);
|
||||
|
||||
m_decode = SGCPU_NONE;
|
||||
m_muxready = true;
|
||||
m_spacep = &space;
|
||||
|
||||
m_decode = decode_address(m_addr_buf);
|
||||
|
||||
if (m_decode == SGCPU_NONE)
|
||||
{
|
||||
// not found - pass on to PEB, 8 bit access with wait states as in TI-99/4A console
|
||||
// PEB gets remaining accesses
|
||||
// HSGPL, EVPC, other devices
|
||||
m_decode = SGCPU_PEB;
|
||||
m_waitcount = 5;
|
||||
m_muxready = false;
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
m_peribox->setaddress_dbin(space, m_addr_buf+1, m_dbin);
|
||||
}
|
||||
|
||||
ready_join();
|
||||
}
|
||||
|
||||
READ16_MEMBER( ti99_4p_state::memread )
|
||||
{
|
||||
int addroff = offset << 1;
|
||||
if (m_rom0 == nullptr) return 0; // premature access
|
||||
int address = 0;
|
||||
UINT8 hbyte = 0;
|
||||
|
||||
UINT16 zone = addroff & 0xe000;
|
||||
UINT16 value = 0;
|
||||
|
||||
if (zone==0x0000)
|
||||
int addr_off8k = m_addr_buf & 0x1fff;
|
||||
|
||||
// If we use the debugger, decode the address now (normally done in setaddress)
|
||||
if (space.debugger_access())
|
||||
{
|
||||
// ROM0
|
||||
value = m_rom0[(addroff & 0x1fff)>>1];
|
||||
return value;
|
||||
}
|
||||
if (zone==0x2000 || zone==0xa000 || zone==0xc000 || zone==0xe000)
|
||||
{
|
||||
value = samsmem_read(space, offset, mem_mask);
|
||||
return value;
|
||||
m_addr_buf = offset << 1;
|
||||
m_decode = decode_address(m_addr_buf);
|
||||
}
|
||||
|
||||
if (zone==0x4000)
|
||||
switch (m_decode)
|
||||
{
|
||||
if (m_internal_dsr)
|
||||
{
|
||||
value = m_dsr[(addroff & 0x1fff)>>1];
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_access_mapper && ((addroff & 0xffe0)==0x4000))
|
||||
{
|
||||
value = m_mapper[offset & 0x000f]<<8;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
case SGCPU_SYSROM:
|
||||
value = m_rom[(ROM0BASE | addr_off8k) >> 1];
|
||||
break;
|
||||
|
||||
case SGCPU_RAM:
|
||||
// Memory read. The AEMS emulation has two address areas: The memory is at locations
|
||||
// 0x2000-0x3fff and 0xa000-0xffff, and the mapper area is at 0x4000-0x401e
|
||||
// (only even addresses).
|
||||
if (m_map_mode)
|
||||
address = (m_mapper[(m_addr_buf & 0xf000)>>12] << 12) | (m_addr_buf & 0x0fff);
|
||||
else // transparent mode
|
||||
address = m_addr_buf;
|
||||
|
||||
value = m_ram[address>>1];
|
||||
break;
|
||||
|
||||
case SGCPU_INTDSR:
|
||||
value = m_rom[(DSRBASE | addr_off8k)>>1];
|
||||
break;
|
||||
|
||||
case SGCPU_MAPPER:
|
||||
value = (m_mapper[m_addr_buf & 0x000f]<<8) & 0xff00;
|
||||
break;
|
||||
|
||||
case SGCPU_ROM6:
|
||||
value = m_rom[((m_rom6_upper? ROM6UBASE : ROM6LBASE) | addr_off8k)>>1];
|
||||
break;
|
||||
case SGCPU_PADRAM:
|
||||
// Scratch pad RAM (16 bit)
|
||||
// 8000 ... 83ff (1K, 4 times the size of the internal RAM of the TI-99/4A)
|
||||
value = m_scratchpad[(m_addr_buf & 0x03ff)>>1];
|
||||
break;
|
||||
|
||||
case SGCPU_PEB:
|
||||
if (space.debugger_access()) return debugger_read(space, offset);
|
||||
// The byte from the odd address has already been read into the latch
|
||||
// Reading the even address now
|
||||
m_peribox->readz(space, m_addr_buf, &hbyte);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
if (TRACE_MEM) logerror("Read even byte from address %04x -> %02x\n", m_addr_buf, hbyte);
|
||||
value = (hbyte<<8) | m_latch;
|
||||
}
|
||||
|
||||
if (zone==0x6000 && m_internal_rom6)
|
||||
{
|
||||
if (m_rom6_bank==0)
|
||||
value = m_rom6a[(addroff & 0x1fff)>>1];
|
||||
else
|
||||
value = m_rom6b[(addroff & 0x1fff)>>1];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// Scratch pad RAM and sound
|
||||
// speech is in peribox
|
||||
// groms are in hsgpl in peribox
|
||||
if (zone==0x8000)
|
||||
{
|
||||
if ((addroff & 0xfff0)==0x8400) // cannot read from sound
|
||||
{
|
||||
value = 0;
|
||||
return value;
|
||||
}
|
||||
if ((addroff & 0xfc00)==0x8000)
|
||||
{
|
||||
value = m_scratchpad[(addroff & 0x03ff)>>1];
|
||||
return value;
|
||||
}
|
||||
// Video: 8800, 8802
|
||||
if ((addroff & 0xfffd)==0x8800)
|
||||
{
|
||||
value = m_video->read16(space, offset, mem_mask);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// If we are here, check the peribox via the datamux
|
||||
// catch-all for unmapped zones
|
||||
value = datamux_read(space, offset, mem_mask);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
WRITE16_MEMBER( ti99_4p_state::memwrite )
|
||||
{
|
||||
// m_cpu->adjust_icount(-4);
|
||||
int address = 0;
|
||||
|
||||
int addroff = offset << 1;
|
||||
UINT16 zone = addroff & 0xe000;
|
||||
|
||||
if (zone==0x0000)
|
||||
// If we use the debugger, decode the address now (normally done in setaddress)
|
||||
if (space.debugger_access())
|
||||
{
|
||||
// ROM0
|
||||
if (TRACE_ILLWRITE) logerror("Ignoring ROM write access at %04x\n", addroff);
|
||||
return;
|
||||
m_addr_buf = offset << 1;
|
||||
m_decode = decode_address(m_addr_buf);
|
||||
}
|
||||
|
||||
if (zone==0x2000 || zone==0xa000 || zone==0xc000 || zone==0xe000)
|
||||
switch (m_decode)
|
||||
{
|
||||
samsmem_write(space, offset, data, mem_mask);
|
||||
return;
|
||||
}
|
||||
case SGCPU_SYSROM:
|
||||
if (TRACE_ILLWRITE) logerror("Ignoring ROM write access at %04x\n", m_addr_buf);
|
||||
break;
|
||||
|
||||
if (zone==0x4000)
|
||||
{
|
||||
if (m_internal_dsr)
|
||||
{
|
||||
if (TRACE_ILLWRITE) logerror("Ignoring DSR write access at %04x\n", addroff);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_access_mapper && ((addroff & 0xffe0)==0x4000))
|
||||
{
|
||||
m_mapper[offset & 0x000f] = data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
case SGCPU_RAM:
|
||||
// see above
|
||||
if (m_map_mode)
|
||||
address = (m_mapper[(m_addr_buf & 0xf000)>>12] << 12) | (m_addr_buf & 0x0fff);
|
||||
else // transparent mode
|
||||
address = m_addr_buf;
|
||||
|
||||
if (zone==0x6000 && m_internal_rom6)
|
||||
{
|
||||
m_rom6_bank = offset & 0x0001;
|
||||
return;
|
||||
}
|
||||
m_ram[address>>1] = data;
|
||||
break;
|
||||
|
||||
// Scratch pad RAM and sound
|
||||
// speech is in peribox
|
||||
// groms are in hsgpl in peribox
|
||||
if (zone==0x8000)
|
||||
{
|
||||
if ((addroff & 0xfff0)==0x8400) //sound write
|
||||
{
|
||||
m_sound->write(space, 0, (data >> 8) & 0xff);
|
||||
return;
|
||||
}
|
||||
if ((addroff & 0xfc00)==0x8000)
|
||||
{
|
||||
m_scratchpad[(addroff & 0x03ff)>>1] = data;
|
||||
return;
|
||||
}
|
||||
// Video: 8C00, 8C02
|
||||
if ((addroff & 0xfffd)==0x8c00)
|
||||
{
|
||||
m_video->write16(space, offset, data, mem_mask);
|
||||
return;
|
||||
}
|
||||
}
|
||||
case SGCPU_INTDSR:
|
||||
if (TRACE_ILLWRITE) logerror("Ignoring DSR write access at %04x\n", m_addr_buf);
|
||||
break;
|
||||
|
||||
// If we are here, check the peribox via the datamux
|
||||
// catch-all for unmapped zones
|
||||
datamux_write(space, offset, data, mem_mask);
|
||||
case SGCPU_MAPPER:
|
||||
m_mapper[(m_addr_buf>>1) & 0x000f] = data; // writing both bytes, but only the first is accepted
|
||||
break;
|
||||
|
||||
case SGCPU_ROM6:
|
||||
// Writing to 6002 sets upper bank
|
||||
m_rom6_upper = (m_addr_buf & 0x0002)!=0;
|
||||
break;
|
||||
|
||||
case SGCPU_PADRAM:
|
||||
// Scratch pad RAM (16 bit)
|
||||
// 8000 ... 83ff (1K, 4 times the size of the internal RAM of the TI-99/4A)
|
||||
m_scratchpad[(m_addr_buf & 0x03ff)>>1] = data;
|
||||
break;
|
||||
|
||||
case SGCPU_PEB:
|
||||
if (space.debugger_access()) { debugger_write(space, offset, data); return; }
|
||||
|
||||
// Writing the even address now (addr)
|
||||
// The databus multplexer puts the even value into the latch and outputs the odd value now.
|
||||
m_latch = (data >> 8) & 0xff;
|
||||
|
||||
// write odd byte
|
||||
if (TRACE_MEM) logerror("datamux: write odd byte to address %04x <- %02x\n", m_addr_buf+1, data & 0xff);
|
||||
m_peribox->write(space, m_addr_buf+1, data & 0xff);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Internal datamux; similar to TI-99/4A. However, here we have just
|
||||
one device, the peripheral box, so it is much simpler.
|
||||
***************************************************************************/
|
||||
/*
|
||||
Used when the debugger is reading values from PEB cards.
|
||||
*/
|
||||
READ16_MEMBER( ti99_4p_state::debugger_read )
|
||||
{
|
||||
UINT8 lval = 0;
|
||||
UINT8 hval = 0;
|
||||
UINT16 addrb = offset << 1;
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
m_peribox->readz(space, addrb+1, &lval);
|
||||
m_peribox->readz(space, addrb, &hval);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
return ((hval << 8)&0xff00) | (lval & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
Used when the debugger is writing values to PEB cards.
|
||||
*/
|
||||
WRITE16_MEMBER( ti99_4p_state::debugger_write )
|
||||
{
|
||||
int addrb = offset << 1;
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
m_peribox->write(space, addrb+1, data & 0xff);
|
||||
m_peribox->write(space, addrb, (data>>8) & 0xff);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
}
|
||||
|
||||
/*
|
||||
Data bus in (DBIN) line from the CPU.
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_4p_state::dbin_line )
|
||||
{
|
||||
m_dbin = (line_state)state;
|
||||
}
|
||||
|
||||
/*
|
||||
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_4p_state::clock_in(int clock)
|
||||
WRITE_LINE_MEMBER( ti99_4p_state::datamux_clock_in )
|
||||
{
|
||||
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) console_ready_dmux(ASSERT_LINE);
|
||||
if (TRACE_MUX) logerror("datamux: wait count %d\n", m_waitcount);
|
||||
if (m_sysready==CLEAR_LINE)
|
||||
{
|
||||
if (TRACE_MUX) logerror("datamux: stalled due to external READY=0\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_dbin==ASSERT_LINE)
|
||||
{
|
||||
// Reading
|
||||
if (state==ASSERT_LINE)
|
||||
{ // raising edge
|
||||
if (--m_waitcount==0)
|
||||
{
|
||||
m_muxready = true;
|
||||
ready_join();
|
||||
}
|
||||
if (m_waitcount==2)
|
||||
{
|
||||
// read odd byte
|
||||
m_peribox->readz(*m_spacep, m_addr_buf+1, &m_latch);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
|
||||
if (TRACE_MEM) logerror("datamux: read odd byte from address %04x -> %02x\n", m_addr_buf+1, m_latch);
|
||||
|
||||
// do the setaddress for the even address
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
m_peribox->setaddress_dbin(*m_spacep, m_addr_buf, m_dbin);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // write access
|
||||
{
|
||||
if (state==ASSERT_LINE)
|
||||
{ // raising edge
|
||||
if (--m_waitcount==0)
|
||||
{
|
||||
m_muxready = true;
|
||||
ready_join();
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // falling edge
|
||||
if (m_waitcount==2)
|
||||
{
|
||||
// do the setaddress for the even address
|
||||
m_peribox->memen_in(ASSERT_LINE);
|
||||
m_peribox->setaddress_dbin(*m_spacep, m_addr_buf, m_dbin);
|
||||
|
||||
// write even byte
|
||||
if (TRACE_MEM) logerror("datamux: write even byte to address %04x <- %02x\n", m_addr_buf, m_latch);
|
||||
m_peribox->write(*m_spacep, m_addr_buf, m_latch);
|
||||
m_peribox->memen_in(CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
// Insert four wait states and let CPU enter wait state
|
||||
m_waitcount = 6;
|
||||
console_ready_dmux(CLEAR_LINE);
|
||||
|
||||
return (hbyte<<8) | m_latch ;
|
||||
}
|
||||
|
||||
/*
|
||||
Write access.
|
||||
TODO: use the 16-bit expansion in the box for suitable cards
|
||||
*/
|
||||
WRITE16_MEMBER( ti99_4p_state::datamux_write )
|
||||
{
|
||||
UINT16 addroff = (offset << 1);
|
||||
// printf("write address = %04x, value = %04x, memmask = %4x\n", addroff, data, mem_mask);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
CRU interface
|
||||
***************************************************************************/
|
||||
@ -528,46 +719,6 @@ READ8_MEMBER( ti99_4p_state::cruread )
|
||||
return value;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
AMS Memory implementation
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
Memory read. The SAMS card has two address areas: The memory is at locations
|
||||
0x2000-0x3fff and 0xa000-0xffff, and the mapper area is at 0x4000-0x401e
|
||||
(only even addresses).
|
||||
*/
|
||||
READ16_MEMBER( ti99_4p_state::samsmem_read )
|
||||
{
|
||||
UINT32 address = 0;
|
||||
int addroff = offset << 1;
|
||||
|
||||
// select memory expansion
|
||||
if (m_map_mode)
|
||||
address = (m_mapper[(addroff>>12) & 0x000f] << 12) + (addroff & 0x0fff);
|
||||
else // transparent mode
|
||||
address = addroff;
|
||||
|
||||
return m_ram[address>>1];
|
||||
}
|
||||
|
||||
/*
|
||||
Memory write
|
||||
*/
|
||||
WRITE16_MEMBER( ti99_4p_state::samsmem_write )
|
||||
{
|
||||
UINT32 address = 0;
|
||||
int addroff = offset << 1;
|
||||
|
||||
// select memory expansion
|
||||
if (m_map_mode)
|
||||
address = (m_mapper[(addroff>>12) & 0x000f] << 12) + (addroff & 0x0fff);
|
||||
else // transparent mode
|
||||
address = addroff;
|
||||
|
||||
m_ram[address>>1] = data;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Keyboard/tape control
|
||||
****************************************************************************/
|
||||
@ -700,15 +851,11 @@ WRITE_LINE_MEMBER( ti99_4p_state::cassette_output )
|
||||
****************************************************************************/
|
||||
|
||||
/*
|
||||
We may have lots of devices pulling down this line; so we should use a AND
|
||||
gate to do it right. On the other hand, when READY is down, there is just
|
||||
no chance to make another device pull down the same line; the CPU just
|
||||
won't access any other device in this time.
|
||||
Combine the external (sysready) and the own (muxready) READY states.
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_4p_state::console_ready )
|
||||
void ti99_4p_state::ready_join()
|
||||
{
|
||||
m_ready_line = state;
|
||||
int combined = (m_ready_line == ASSERT_LINE && m_ready_line_dmux == ASSERT_LINE)? ASSERT_LINE : CLEAR_LINE;
|
||||
int combined = (m_sysready == ASSERT_LINE && m_muxready)? ASSERT_LINE : CLEAR_LINE;
|
||||
|
||||
if (TRACE_READY)
|
||||
{
|
||||
@ -719,21 +866,17 @@ WRITE_LINE_MEMBER( ti99_4p_state::console_ready )
|
||||
}
|
||||
|
||||
/*
|
||||
The exception of the above rule. Memory access over the datamux also operates
|
||||
the READY line, and the datamux raises READY depending on the clock pulse.
|
||||
So we must make sure this does not interfere.
|
||||
Incoming READY line from other cards in the Peripheral Expansion Box.
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_4p_state::console_ready_dmux )
|
||||
WRITE_LINE_MEMBER( ti99_4p_state::ready_line )
|
||||
{
|
||||
m_ready_line_dmux = state;
|
||||
int combined = (m_ready_line == ASSERT_LINE && m_ready_line_dmux == ASSERT_LINE)? ASSERT_LINE : CLEAR_LINE;
|
||||
|
||||
if (TRACE_READY)
|
||||
{
|
||||
if (m_ready_prev != combined) logerror("READY dmux level = %d\n", state);
|
||||
if (state != m_sysready) logerror("READY line from PBox = %d\n", state);
|
||||
}
|
||||
m_ready_prev = combined;
|
||||
m_cpu->set_ready(combined);
|
||||
m_sysready = (line_state)state;
|
||||
// Also propagate to CPU via driver
|
||||
ready_join();
|
||||
}
|
||||
|
||||
void ti99_4p_state::set_9901_int( int line, line_state state)
|
||||
@ -760,7 +903,8 @@ WRITE_LINE_MEMBER( ti99_4p_state::notconnected )
|
||||
*/
|
||||
WRITE_LINE_MEMBER( ti99_4p_state::clock_out )
|
||||
{
|
||||
clock_in(state);
|
||||
datamux_clock_in(state);
|
||||
m_peribox->clock_in(state);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( ti99_4p_state::tms9901_interrupt )
|
||||
@ -781,7 +925,7 @@ READ8_MEMBER( ti99_4p_state::interrupt_level )
|
||||
WRITE8_MEMBER( ti99_4p_state::external_operation )
|
||||
{
|
||||
static const char* extop[8] = { "inv1", "inv2", "IDLE", "RSET", "inv3", "CKON", "CKOF", "LREX" };
|
||||
logerror("External operation %s not implemented on the SGCPU board\n", extop[offset]);
|
||||
if (offset != IDLE_OP) logerror("External operation %s not implemented on the SGCPU board\n", extop[offset]);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@ -796,19 +940,16 @@ void ti99_4p_state::machine_start()
|
||||
|
||||
m_firstjoy = 6;
|
||||
|
||||
m_ready_line = m_ready_line_dmux = ASSERT_LINE;
|
||||
m_sysready = ASSERT_LINE;
|
||||
m_muxready = true;
|
||||
|
||||
UINT16 *rom = (UINT16*)(memregion("maincpu")->base());
|
||||
m_rom0 = rom + 0x2000;
|
||||
m_dsr = rom + 0x6000;
|
||||
m_rom6a = rom + 0x3000;
|
||||
m_rom6b = rom + 0x7000;
|
||||
m_rom = (UINT16*)(memregion("maincpu")->base());
|
||||
}
|
||||
|
||||
/*
|
||||
set the state of int2 (called by the v9938)
|
||||
*/
|
||||
WRITE_LINE_MEMBER(ti99_4p_state::set_tms9901_INT2_from_v9938)
|
||||
WRITE_LINE_MEMBER(ti99_4p_state::video_interrupt_in)
|
||||
{
|
||||
set_9901_int(2, (line_state)state);
|
||||
}
|
||||
@ -836,12 +977,7 @@ static MACHINE_CONFIG_START( ti99_4p_60hz, ti99_4p_state )
|
||||
MCFG_TMS99xx_EXTOP_HANDLER( WRITE8(ti99_4p_state, external_operation) )
|
||||
MCFG_TMS99xx_INTLEVEL_HANDLER( READ8(ti99_4p_state, interrupt_level) )
|
||||
MCFG_TMS99xx_CLKOUT_HANDLER( WRITELINE(ti99_4p_state, clock_out) )
|
||||
|
||||
/* video hardware */
|
||||
MCFG_DEVICE_ADD(VIDEO_SYSTEM_TAG, V9938VIDEO, 0)
|
||||
MCFG_V9938_ADD(VDP_TAG, SCREEN_TAG, 0x20000, XTAL_21_4772MHz) /* typical 9938 clock, not verified */
|
||||
MCFG_V99X8_INTERRUPT_CALLBACK(WRITELINE(ti99_4p_state, set_tms9901_INT2_from_v9938))
|
||||
MCFG_V99X8_SCREEN_ADD_NTSC(SCREEN_TAG, VDP_TAG, XTAL_21_4772MHz)
|
||||
MCFG_TMS99xx_DBIN_HANDLER( WRITELINE(ti99_4p_state, dbin_line) )
|
||||
|
||||
// tms9901
|
||||
MCFG_DEVICE_ADD(TMS9901_TAG, TMS9901, 3000000)
|
||||
@ -858,13 +994,10 @@ static MACHINE_CONFIG_START( ti99_4p_60hz, ti99_4p_state )
|
||||
MCFG_DEVICE_ADD( PERIBOX_TAG, PERIBOX_SG, 0)
|
||||
MCFG_PERIBOX_INTA_HANDLER( WRITELINE(ti99_4p_state, extint) )
|
||||
MCFG_PERIBOX_INTB_HANDLER( WRITELINE(ti99_4p_state, notconnected) )
|
||||
MCFG_PERIBOX_READY_HANDLER( WRITELINE(ti99_4p_state, console_ready) )
|
||||
MCFG_PERIBOX_READY_HANDLER( WRITELINE(ti99_4p_state, ready_line) )
|
||||
|
||||
// Sound hardware
|
||||
MCFG_SPEAKER_STANDARD_MONO("sound_out")
|
||||
MCFG_SOUND_ADD(TISOUNDCHIP_TAG, SN94624, 3579545/8) /* 3.579545 MHz */
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "sound_out", 0.75)
|
||||
MCFG_SN76496_READY_HANDLER( WRITELINE(ti99_4p_state, console_ready) )
|
||||
// The SGCPU actually makes use of this pin which was unused before
|
||||
MCFG_PERIBOX_LCP_HANDLER( WRITELINE(ti99_4p_state, video_interrupt_in) )
|
||||
|
||||
// Cassette drives
|
||||
MCFG_SPEAKER_STANDARD_MONO("cass_out")
|
||||
@ -887,4 +1020,4 @@ ROM_START(ti99_4p)
|
||||
ROM_END
|
||||
|
||||
/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */
|
||||
COMP( 1996, ti99_4p, 0, 0, ti99_4p_60hz, ti99_4p, driver_device, 0, "System 99 Users Group", "SGCPU (a.k.a. 99/4P)" , 0 )
|
||||
COMP( 1996, ti99_4p, 0, 0, ti99_4p_60hz, ti99_4p, driver_device, 0, "System-99 User Group", "SGCPU (aka TI-99/4P)" , 0 )
|
||||
|
@ -46,7 +46,7 @@
|
||||
#include "machine/tms9901.h"
|
||||
#include "imagedev/cassette.h"
|
||||
|
||||
#include "bus/ti99x/videowrp.h"
|
||||
#include "bus/ti99x/ti99defs.h"
|
||||
#include "bus/ti99x/datamux.h"
|
||||
#include "bus/ti99x/gromport.h"
|
||||
#include "bus/ti99x/joyport.h"
|
||||
@ -73,7 +73,7 @@ public:
|
||||
m_peribox(*this, PERIBOX_TAG),
|
||||
m_joyport(*this, JOYPORT_TAG),
|
||||
m_datamux(*this, DATAMUX_TAG),
|
||||
m_video(*this, VIDEO_SYSTEM_TAG),
|
||||
m_video(*this, VDP_TAG),
|
||||
m_cassette1(*this, "cassette"),
|
||||
m_cassette2(*this, "cassette2")
|
||||
{ }
|
||||
@ -130,6 +130,7 @@ public:
|
||||
DECLARE_INPUT_CHANGED_MEMBER( load_interrupt );
|
||||
|
||||
// Used by EVPC
|
||||
DECLARE_WRITE_LINE_MEMBER( video_interrupt_evpc_in );
|
||||
void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
|
||||
|
||||
private:
|
||||
@ -157,7 +158,7 @@ private:
|
||||
required_device<peribox_device> m_peribox;
|
||||
required_device<joyport_device> m_joyport;
|
||||
required_device<ti99_datamux_device> m_datamux;
|
||||
required_device<ti_video_device> m_video;
|
||||
optional_device<tms9928a_device> m_video;
|
||||
required_device<cassette_image_device> m_cassette1;
|
||||
required_device<cassette_image_device> m_cassette2;
|
||||
|
||||
@ -655,6 +656,13 @@ void ti99_4x_state::device_timer(emu_timer &timer, device_timer_id id, int param
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
WRITE_LINE_MEMBER( ti99_4x_state::video_interrupt_evpc_in )
|
||||
{
|
||||
if (TRACE_INTERRUPTS) logerror("ti99_4x: VDP INT2 from EVPC on tms9901, level=%d\n", state);
|
||||
m_int2 = (line_state)state;
|
||||
m_tms9901->set_single_int(2, state);
|
||||
}
|
||||
|
||||
/*
|
||||
set the state of TMS9901's INT2 (called by the tms9928 core)
|
||||
*/
|
||||
@ -754,7 +762,7 @@ WRITE_LINE_MEMBER( ti99_4x_state::console_reset )
|
||||
{
|
||||
logerror("ti99_4x: Console reset line = %d\n", state);
|
||||
m_cpu->set_input_line(INT_9900_RESET, state);
|
||||
m_video->reset_vdp(state);
|
||||
m_video->reset_line(state);
|
||||
}
|
||||
}
|
||||
|
||||
@ -770,6 +778,37 @@ WRITE_LINE_MEMBER( ti99_4x_state::notconnected )
|
||||
if (TRACE_INTERRUPTS) logerror("ti99_4x: Setting a not connected line ... ignored\n");
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
External clock connector. This is actually a separate cable lead going from
|
||||
the EPVC in the PEB to a pin inside the console. This cable sends the
|
||||
video interrupt from the v9938 on the EVPC into the console.
|
||||
This workaround must be done on the real system because the peripheral
|
||||
box and its connector were not designed to deliver a video interrupt signal.
|
||||
This was fixed with the EVPC2 which uses the external interrupt EXTINT
|
||||
with a special firmware (DSR).
|
||||
|
||||
Emulation detail: We are using a separate device class in order to avoid
|
||||
exposing the console class to the external class.
|
||||
*/
|
||||
evpc_clock_connector::evpc_clock_connector(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, EVPC_CONN, "EVPC clock connector", tag, owner, clock, "ti99_evpc_clock", __FILE__)
|
||||
{
|
||||
}
|
||||
|
||||
void evpc_clock_connector::device_start()
|
||||
{
|
||||
m_console = downcast<ti99_4x_state*>(owner());
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( evpc_clock_connector::vclock_line )
|
||||
{
|
||||
m_console->video_interrupt_in(state);
|
||||
};
|
||||
|
||||
const device_type EVPC_CONN = &device_creator<evpc_clock_connector>;
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
Machine definitions
|
||||
******************************************************************************/
|
||||
@ -863,14 +902,24 @@ 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, gromclk_in)
|
||||
MCFG_DEVICE_ADD( VDP_TAG, TMS9918, XTAL_10_738635MHz / 2 ) \
|
||||
MCFG_TMS9928A_VRAM_SIZE(0x4000) \
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(ti99_4x_state, video_interrupt_in)) \
|
||||
MCFG_TMS9928A_OUT_GROMCLK_CB(WRITELINE(ti99_4x_state, gromclk_in)) \
|
||||
MCFG_TMS9928A_SCREEN_ADD_NTSC( SCREEN_TAG ) \
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
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, gromclk_in)
|
||||
MCFG_DEVICE_ADD( VDP_TAG, TMS9929, XTAL_10_738635MHz / 2 ) \
|
||||
MCFG_TMS9928A_VRAM_SIZE(0x4000) \
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(ti99_4x_state, video_interrupt_in)) \
|
||||
MCFG_TMS9928A_OUT_GROMCLK_CB(WRITELINE(ti99_4x_state, gromclk_in)) \
|
||||
MCFG_TMS9928A_SCREEN_ADD_PAL( SCREEN_TAG ) \
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/**********************************************************************
|
||||
@ -961,14 +1010,24 @@ 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, gromclk_in)
|
||||
MCFG_DEVICE_ADD( VDP_TAG, TMS9918A, XTAL_10_738635MHz / 2 ) \
|
||||
MCFG_TMS9928A_VRAM_SIZE(0x4000) \
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(ti99_4x_state, video_interrupt_in)) \
|
||||
MCFG_TMS9928A_OUT_GROMCLK_CB(WRITELINE(ti99_4x_state, gromclk_in)) \
|
||||
MCFG_TMS9928A_SCREEN_ADD_NTSC( SCREEN_TAG ) \
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
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, gromclk_in)
|
||||
MCFG_DEVICE_ADD( VDP_TAG, TMS9929A, XTAL_10_738635MHz / 2 ) \
|
||||
MCFG_TMS9928A_VRAM_SIZE(0x4000) \
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(ti99_4x_state, video_interrupt_in)) \
|
||||
MCFG_TMS9928A_OUT_GROMCLK_CB(WRITELINE(ti99_4x_state, gromclk_in)) \
|
||||
MCFG_TMS9928A_SCREEN_ADD_PAL( SCREEN_TAG ) \
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/************************************************************************
|
||||
@ -996,19 +1055,32 @@ 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, gromclk_in)
|
||||
MCFG_DEVICE_ADD( VDP_TAG, TMS9918A, XTAL_10_738635MHz / 2 ) \
|
||||
MCFG_TMS9928A_VRAM_SIZE(0x4000) \
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(ti99_4x_state, video_interrupt_in)) \
|
||||
MCFG_TMS9928A_OUT_GROMCLK_CB(WRITELINE(ti99_4x_state, gromclk_in)) \
|
||||
MCFG_TMS9928A_SCREEN_ADD_NTSC( SCREEN_TAG ) \
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
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, gromclk_in)
|
||||
MCFG_DEVICE_ADD( VDP_TAG, TMS9929A, XTAL_10_738635MHz / 2 ) \
|
||||
MCFG_TMS9928A_VRAM_SIZE(0x4000) \
|
||||
MCFG_TMS9928A_OUT_INT_LINE_CB(WRITELINE(ti99_4x_state, video_interrupt_in)) \
|
||||
MCFG_TMS9928A_OUT_GROMCLK_CB(WRITELINE(ti99_4x_state, gromclk_in)) \
|
||||
MCFG_TMS9928A_SCREEN_ADD_PAL( SCREEN_TAG ) \
|
||||
MCFG_SCREEN_UPDATE_DEVICE( VDP_TAG, tms9928a_device, screen_update )
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
/************************************************************************
|
||||
TI-99/4A with 80-column support. Actually a separate expansion card (EVPC),
|
||||
replacing the console video processor.
|
||||
|
||||
Note that the sound chip is also moved to this card, because the SGCPU,
|
||||
which is intended to use the EVPC, does not have an own sound chip.
|
||||
*************************************************************************/
|
||||
|
||||
MACHINE_START_MEMBER(ti99_4x_state, ti99_4ev)
|
||||
@ -1043,12 +1115,6 @@ static MACHINE_CONFIG_START( ti99_4ev_60hz, ti99_4x_state )
|
||||
MCFG_MACHINE_START_OVERRIDE(ti99_4x_state, ti99_4ev )
|
||||
MCFG_MACHINE_RESET_OVERRIDE(ti99_4x_state, ti99_4ev )
|
||||
|
||||
/* video hardware */
|
||||
MCFG_DEVICE_ADD(VIDEO_SYSTEM_TAG, V9938VIDEO, 0)
|
||||
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)
|
||||
|
||||
/* Main board */
|
||||
MCFG_DEVICE_ADD(TMS9901_TAG, TMS9901, 3000000)
|
||||
MCFG_TMS9901_READBLOCK_HANDLER( READ8(ti99_4x_state, read_by_9901) )
|
||||
@ -1068,6 +1134,9 @@ static MACHINE_CONFIG_START( ti99_4ev_60hz, ti99_4x_state )
|
||||
MCFG_GROMPORT_READY_HANDLER( WRITELINE(ti99_4x_state, console_ready_cart) )
|
||||
MCFG_GROMPORT_RESET_HANDLER( WRITELINE(ti99_4x_state, console_reset) )
|
||||
|
||||
// EVPC connector
|
||||
MCFG_ADD_EVPC_CONNECTOR( EVPC_CONN_TAG, WRITELINE( ti99_4x_state, video_interrupt_evpc_in ) )
|
||||
|
||||
/* Software list */
|
||||
MCFG_SOFTWARE_LIST_ADD("cart_list_ti99", "ti99_cart")
|
||||
|
||||
@ -1077,12 +1146,6 @@ static MACHINE_CONFIG_START( ti99_4ev_60hz, ti99_4x_state )
|
||||
MCFG_PERIBOX_INTB_HANDLER( WRITELINE(ti99_4x_state, notconnected) )
|
||||
MCFG_PERIBOX_READY_HANDLER( DEVWRITELINE(DATAMUX_TAG, ti99_datamux_device, ready_line) )
|
||||
|
||||
// Sound hardware
|
||||
MCFG_SPEAKER_STANDARD_MONO("sound_out")
|
||||
MCFG_SOUND_ADD(TISOUNDCHIP_TAG, SN94624, 3579545/8) /* 3.579545 MHz */
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "sound_out", 0.75)
|
||||
MCFG_SN76496_READY_HANDLER( WRITELINE(ti99_4x_state, console_ready_sound) )
|
||||
|
||||
/* Cassette drives */
|
||||
MCFG_SPEAKER_STANDARD_MONO("cass_out")
|
||||
MCFG_CASSETTE_ADD( "cassette" )
|
||||
|
@ -182,7 +182,6 @@ Known Issues (MZ, 2010-11-07)
|
||||
#include "imagedev/cassette.h"
|
||||
|
||||
#include "bus/ti99x/998board.h"
|
||||
#include "bus/ti99x/videowrp.h"
|
||||
#include "bus/ti99x/gromport.h"
|
||||
#include "bus/ti99x/joyport.h"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user