summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/ti99_peb/tn_usbsm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/ti99_peb/tn_usbsm.c')
-rw-r--r--src/devices/bus/ti99_peb/tn_usbsm.c345
1 files changed, 345 insertions, 0 deletions
diff --git a/src/devices/bus/ti99_peb/tn_usbsm.c b/src/devices/bus/ti99_peb/tn_usbsm.c
new file mode 100644
index 00000000000..f3a911af0f2
--- /dev/null
+++ b/src/devices/bus/ti99_peb/tn_usbsm.c
@@ -0,0 +1,345 @@
+// license:LGPL-2.1+
+// copyright-holders:Michael Zapf
+/****************************************************************************
+
+ Thierry Nouspikel's USB-SmartMedia card emulation
+
+ This card features three USB ports (two host and one device) and a
+ SmartMedia interface. The original prototype was designed by Thierry
+ Nouspikel, and its description was published in 2003; a small series of
+ approximately 100 printed-circuit boards was ordered shortly afterwards
+ by various TI users.
+
+ The specs have been published in <http://www.nouspikel.com/ti99/usb.html>.
+
+ The USB interface uses a Philips ISP1161A USB controller that supports
+ USB 2.0 full-speed (12 Mbit/s) and low-speed (1.5 Mbit/s) I/O (high speed
+ (480 Mbits/sec) is not supported, but it is hardly a problem since TI99 is
+ too slow to take advantage from high speed). The SmartMedia interface uses
+ a few TTL buffers. The card also includes an 8MByte StrataFlash FEEPROM
+ and 1MByte of SRAM for DSR use.
+
+ The card has a 8-bit->16-bit demultiplexer that can be set-up to assume
+ either that the LSByte of a word is accessed first or that the MSByte of a word
+ is accessed first. The former is true with ti-99/4(a), the latter with the
+ tms9995 CPU used by Geneve and ti-99/8.
+
+ TODO:
+ * Test SmartMedia support
+ * Implement USB controller and assorted USB devices
+ * Save DSR FEEPROM to disk
+
+ Raphael Nabet, 2004.
+
+ Michael Zapf
+ September 2010: Rewritten as device
+ February 2012: Rewritten as class
+
+ FIXME: Completely untested and likely to be broken
+
+*****************************************************************************/
+
+#include "tn_usbsm.h"
+
+#define STRATA_TAG "strata"
+
+enum
+{
+ IO_REGS_ENABLE = 0x02,
+ INT_ENABLE = 0x04,
+ SM_ENABLE = 0x08,
+ FEEPROM_WRITE_ENABLE = 0x10
+};
+
+nouspikel_usb_smartmedia_device::nouspikel_usb_smartmedia_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+: ti_expansion_card_device(mconfig, TI99_USBSM, "Nouspikel USB/Smartmedia card", tag, owner, clock, "ti99_usbsm", __FILE__),
+ m_smartmedia(*this, "smartmedia"),
+ m_flash(*this, STRATA_TAG)
+{
+}
+
+/*
+ CRU read
+*/
+READ8Z_MEMBER(nouspikel_usb_smartmedia_device::crureadz)
+{
+ if ((offset & 0xff00)==m_cru_base)
+ {
+ UINT8 reply = 0;
+ offset &= 3;
+
+ if (offset == 0)
+ {
+ // bit
+ // 0 >1x00 0: USB Host controller requests interrupt.
+ // 1 >1x02 0: USB Device controller requests interrupt.
+ // 2 >1x04 1: USB Host controller suspended.
+ // 3 >1x06 1: USB Device controller suspended.
+ // 4 >1x08 0: Strata FEEPROM is busy.
+ // 1: Strata FEEPROM is ready.
+ // 5 >1x0A 0: SmartMedia card is busy.
+ // 1: SmartMedia card absent or ready.
+ // 6 >1x0C 0: No SmartMedia card present.
+ // 1: A card is in the connector.
+ // 7 >1x0E 0: SmartMedia card is protected.
+ // 1: Card absent or not protected.
+
+ reply = 0x33;
+ if (!m_smartmedia->is_present())
+ reply |= 0xc0;
+ else if (!m_smartmedia->is_protected())
+ reply |= 0x80;
+ }
+ *value = reply;
+ }
+}
+
+/*
+ CRU write
+*/
+WRITE8_MEMBER(nouspikel_usb_smartmedia_device::cruwrite)
+{
+ if ((offset & 0xff00)==m_cru_base)
+ {
+ int bit = (offset >> 1) & 0x1f;
+
+ switch (bit)
+ {
+ case 0:
+ m_selected = data;
+ break;
+ case 1:
+ // enable I/O registers
+ m_enable_io = data;
+ break;
+ case 2:
+ // enable interrupts
+ m_enable_int = data;
+ break;
+ case 3:
+ // enable SmartMedia card
+ m_enable_sm = data;
+ break;
+ case 4:
+ // enable FEEPROM writes (and disable reads)
+ m_write_flash = data;
+ break;
+ case 5: /* FEEPROM page */
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ if (data)
+ m_feeprom_page |= 1 << (bit-5);
+ else
+ m_feeprom_page &= ~ (1 << (bit-5));
+ break;
+
+ case 16: /* SRAM page */
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ if (data)
+ m_sram_page |= 1 << (bit-16);
+ else
+ m_sram_page &= ~ (1 << (bit-16));
+ break;
+ }
+ }
+}
+
+/*
+ Memory read
+ TODO: Check whether AMA/B/C is actually checked
+*/
+READ8Z_MEMBER(nouspikel_usb_smartmedia_device::readz)
+{
+ if (space.debugger_access()) return;
+
+ if (((offset & m_select_mask)==m_select_value) && m_selected)
+ {
+ if (m_tms9995_mode ? (!(offset & 1)) : (offset & 1))
+ {
+ // first read triggers 16-bit read cycle
+
+ if (offset < 0x5000)
+ {
+ // 0x4000-0x4fff range
+ if (m_enable_io && (offset >= 0x4ff0))
+ {
+ // SmartMedia interface (4ff0-4ff7)
+ if ((offset & 8) == 0)
+ m_input_latch = m_smartmedia->data_r() << 8;
+ }
+ else
+ {
+ // FEEPROM
+ if (!m_write_flash)
+ m_input_latch = m_flash->read16(space, (offset>>1)&0xffff);
+ }
+ }
+ else
+ {
+ // 0x5000-0x5fff range
+ if (m_enable_io && (offset >= 0x5ff0))
+ {
+ // USB controller. Not implemented.
+ logerror("tn_usbsm: Reading from USB\n");
+ }
+ else
+ {
+ // SRAM
+ m_input_latch = m_ram[m_sram_page*0x800+((offset>>1)&0x07ff)];
+ }
+ }
+ }
+
+ // return latched input
+ *value = ((offset & 1) ? (m_input_latch) : (m_input_latch >> 8)) & 0xff;
+ }
+}
+
+/*
+ Memory write. The controller is 16 bit, so we need to demultiplex again.
+*/
+WRITE8_MEMBER(nouspikel_usb_smartmedia_device::write)
+{
+ if (space.debugger_access()) return;
+
+ if (((offset & m_select_mask)==m_select_value) && m_selected)
+ {
+ /* latch write */
+ if (offset & 1)
+ m_output_latch = (m_output_latch & 0xff00) | data;
+ else
+ m_output_latch = (m_output_latch & 0x00ff) | (data << 8);
+
+ if ((m_tms9995_mode)? (offset & 1) : (!(offset & 1)))
+ {
+ // second write triggers 16-bit write cycle
+ if (offset < 0x5000)
+ {
+ // 0x4000-0x4fff range
+ if (m_enable_io && (offset >= 0x4ff0))
+ {
+ // SmartMedia interface
+ switch (offset & 3)
+ {
+ case 0:
+ m_smartmedia->data_w(m_output_latch >> 8);
+ break;
+ case 1:
+ m_smartmedia->address_w(m_output_latch >> 8);
+ break;
+ case 2:
+ m_smartmedia->command_w(m_output_latch >> 8);
+ break;
+ case 3:
+ /* bogus, don't use(?) */
+ break;
+ }
+ }
+ else
+ { // FEEPROM
+ if (m_write_flash)
+ m_flash->write16(space, (offset>>1)&0xffff, m_output_latch);
+ }
+ }
+ else
+ { /* 0x5000-0x5fff range */
+ if (m_enable_io && (offset >= 0x5ff0))
+ {
+ // USB controller. Not implemented.
+ logerror("tn_usbsm: Writing to USB controller.\n");
+ }
+ else
+ { // SRAM
+ m_ram[m_sram_page*0x800+((offset>>1) & 0x07ff)] = m_output_latch;
+ }
+ }
+ }
+ }
+}
+
+void nouspikel_usb_smartmedia_device::device_start()
+{
+ m_ram.resize(0x80000/2);
+}
+
+void nouspikel_usb_smartmedia_device::device_reset()
+{
+ m_feeprom_page = 0;
+ m_sram_page = 0;
+ m_cru_register = 0;
+ m_tms9995_mode = (ioport("BYTEORDER")->read() == 0x01);
+ m_enable_io = false;
+ m_enable_int = false;
+ m_enable_sm = false;
+ m_write_flash = false;
+
+ if (m_genmod)
+ {
+ m_select_mask = 0x1fe000;
+ m_select_value = 0x174000;
+ }
+ else
+ {
+ m_select_mask = 0x7e000;
+ m_select_value = 0x74000;
+ }
+ m_selected = false;
+
+ m_cru_base = ioport("CRUUSBSM")->read();
+}
+
+INPUT_PORTS_START( tn_usbsm )
+ PORT_START( "CRUUSBSM" )
+ PORT_DIPNAME( 0x1f00, 0x1600, "USB/Smartmedia CRU base" )
+ PORT_DIPSETTING( 0x1000, "1000" )
+ PORT_DIPSETTING( 0x1100, "1100" )
+ PORT_DIPSETTING( 0x1200, "1200" )
+ PORT_DIPSETTING( 0x1300, "1300" )
+ PORT_DIPSETTING( 0x1400, "1400" )
+ PORT_DIPSETTING( 0x1500, "1500" )
+ PORT_DIPSETTING( 0x1600, "1600" )
+ PORT_DIPSETTING( 0x1700, "1700" )
+ PORT_DIPSETTING( 0x1800, "1800" )
+ PORT_DIPSETTING( 0x1900, "1900" )
+ PORT_DIPSETTING( 0x1a00, "1A00" )
+ PORT_DIPSETTING( 0x1b00, "1B00" )
+ PORT_DIPSETTING( 0x1c00, "1C00" )
+ PORT_DIPSETTING( 0x1d00, "1D00" )
+ PORT_DIPSETTING( 0x1e00, "1E00" )
+ PORT_DIPSETTING( 0x1f00, "1F00" )
+ PORT_START( "BYTEORDER" )
+ PORT_DIPNAME( 0x01, 0x00, "Multiplex mode" )
+ PORT_DIPSETTING( 0x00, "TI mode")
+ PORT_DIPSETTING( 0x01, "Geneve mode")
+INPUT_PORTS_END
+
+MACHINE_CONFIG_FRAGMENT( tn_usbsm )
+ MCFG_DEVICE_ADD("smartmedia", SMARTMEDIA, 0)
+ MCFG_STRATAFLASH_ADD(STRATA_TAG)
+MACHINE_CONFIG_END
+
+machine_config_constructor nouspikel_usb_smartmedia_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( tn_usbsm );
+}
+
+ioport_constructor nouspikel_usb_smartmedia_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(tn_usbsm);
+}
+
+const device_type TI99_USBSM = &device_creator<nouspikel_usb_smartmedia_device>;