summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/ti99_peb/tn_ide.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/ti99_peb/tn_ide.c')
-rw-r--r--src/devices/bus/ti99_peb/tn_ide.c382
1 files changed, 382 insertions, 0 deletions
diff --git a/src/devices/bus/ti99_peb/tn_ide.c b/src/devices/bus/ti99_peb/tn_ide.c
new file mode 100644
index 00000000000..10e69ace518
--- /dev/null
+++ b/src/devices/bus/ti99_peb/tn_ide.c
@@ -0,0 +1,382 @@
+// license:LGPL-2.1+
+// copyright-holders:Michael Zapf
+/****************************************************************************
+
+ Thierry Nouspikel's IDE card emulation
+
+ This card is just a prototype. It has been designed by Thierry Nouspikel,
+ and its description was published in 2001. The card has been revised in
+ 2004.
+
+ The specs have been published in <http://www.nouspikel.com/ti99/ide.html>.
+
+ The IDE interface is quite simple, since it only implements PIO transfer.
+ The card includes a clock chip to timestamp files, and an SRAM for the DSR.
+ It should be possible to use a battery backed DSR SRAM, but since the clock
+ chip includes 4kb of battery-backed RAM, a bootstrap loader can be saved in
+ the clock SRAM in order to load the DSR from the HD when the computer
+ starts.
+
+ Raphael Nabet, 2002-2004.
+
+ Michael Zapf
+ September 2010: Rewritten as device
+ February 2012: Rewritten as class
+
+ FIXME: Completely untested and likely to be broken
+
+*****************************************************************************/
+
+#include "emu.h"
+#include "peribox.h"
+#include "machine/ataintf.h"
+#include "tn_ide.h"
+
+#define CRU_BASE 0x1000
+
+#define BUFFER_TAG "ram"
+
+/* previously 0xff */
+#define PAGE_MASK 0x3f
+
+enum
+{
+ cru_reg_page_switching = 0x04,
+ cru_reg_page_0 = 0x08,
+ /*cru_reg_rambo = 0x10,*/ /* not emulated */
+ cru_reg_wp = 0x20,
+ cru_reg_int_en = 0x40,
+ cru_reg_reset = 0x80
+};
+
+nouspikel_ide_interface_device::nouspikel_ide_interface_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : ti_expansion_card_device(mconfig, TI99_IDE, "Nouspikel IDE interface card", tag, owner, clock, "ti99_ide", __FILE__),
+ m_ata(*this, "ata")
+{
+}
+
+/*
+ CRU read
+*/
+READ8Z_MEMBER(nouspikel_ide_interface_device::crureadz)
+{
+ UINT8 reply = 0;
+ if ((offset & 0xff00)==m_cru_base)
+ {
+ int bit = (offset >> 4) & 7;
+
+ if (bit==0)
+ {
+ reply = m_cru_register & 0x30;
+ reply |= 8; /* IDE bus IORDY always set */
+ if (!m_clk_irq)
+ reply |= 4;
+ if (m_sram_enable_dip)
+ reply |= 2;
+ if (!m_ata_irq)
+ reply |= 1;
+ }
+ *value = reply;
+ }
+}
+
+/*
+ CRU write
+*/
+WRITE8_MEMBER(nouspikel_ide_interface_device::cruwrite)
+{
+ if ((offset & 0xff00)==m_cru_base)
+ {
+ int bit = (offset >>1) & 7;
+ switch (bit)
+ {
+ case 0:
+ m_selected = (data!=0);
+
+ case 1: // enable SRAM or registers in 0x4000-0x40ff
+ m_sram_enable = (data!=0);
+ break;
+
+ case 2: // enable SRAM page switching
+ case 3: // force SRAM page 0
+ case 4: // enable SRAM in 0x6000-0x7000 ("RAMBO" mode)
+ case 5: // write-protect RAM
+ case 6: // irq and reset enable
+ case 7: // reset drive
+ if (data!=0)
+ m_cru_register |= 1 << bit;
+ else
+ m_cru_register &= ~(1 << bit);
+
+ if (bit == 6)
+ m_slot->set_inta((m_cru_register & cru_reg_int_en) && m_ata_irq);
+
+ if ((bit == 6) || (bit == 7))
+ if ((m_cru_register & cru_reg_int_en) && !(m_cru_register & cru_reg_reset))
+ m_ata->reset();
+ break;
+ }
+ }
+}
+
+/*
+ Memory read
+*/
+READ8Z_MEMBER(nouspikel_ide_interface_device::readz)
+{
+ UINT8 reply = 0;
+ if (space.debugger_access()) return;
+
+ if (((offset & m_select_mask)==m_select_value) && m_selected)
+ {
+ int addr = offset & 0x1fff;
+
+ if ((addr <= 0xff) && (m_sram_enable == m_sram_enable_dip))
+ { /* registers */
+ switch ((addr >> 5) & 0x3)
+ {
+ case 0: /* RTC RAM */
+ if (addr & 0x80)
+ /* RTC RAM page register */
+ reply = m_rtc->xram_r(machine().driver_data()->generic_space(),(addr & 0x1f) | 0x20);
+ else
+ /* RTC RAM read */
+ reply = m_rtc->xram_r(machine().driver_data()->generic_space(),addr);
+ break;
+ case 1: /* RTC registers */
+ if (addr & 0x10)
+ /* register data */
+ reply = m_rtc->rtc_r(machine().driver_data()->generic_space(),1);
+ else
+ /* register select */
+ reply = m_rtc->rtc_r(machine().driver_data()->generic_space(),0);
+ break;
+ case 2: /* IDE registers set 1 (CS1Fx) */
+ if (m_tms9995_mode ? (!(addr & 1)) : (addr & 1))
+ { /* first read triggers 16-bit read cycle */
+ m_input_latch = (! (addr & 0x10)) ? m_ata->read_cs0(space, (addr >> 1) & 0x7, 0xffff) : 0;
+ }
+
+ /* return latched input */
+ /*reply = (addr & 1) ? input_latch : (input_latch >> 8);*/
+ /* return latched input - bytes are swapped in 2004 IDE card */
+ reply = ((addr & 1) ? (m_input_latch >> 8) : m_input_latch) & 0xff;
+ break;
+ case 3: /* IDE registers set 2 (CS3Fx) */
+ if (m_tms9995_mode ? (!(addr & 1)) : (addr & 1))
+ { /* first read triggers 16-bit read cycle */
+ m_input_latch = (! (addr & 0x10)) ? m_ata->read_cs1(space, (addr >> 1) & 0x7, 0xffff) : 0;
+ }
+
+ /* return latched input */
+ /*reply = (addr & 1) ? input_latch : (input_latch >> 8);*/
+ /* return latched input - bytes are swapped in 2004 IDE card */
+ reply = ((addr & 1) ? (m_input_latch >> 8) : m_input_latch) & 0xff;
+ break;
+ }
+ }
+ else
+ { /* sram */
+ if ((m_cru_register & cru_reg_page_0) || (addr >= 0x1000))
+ reply = m_ram[addr+0x2000 * m_cur_page];
+ else
+ reply = m_ram[addr];
+ }
+ *value = reply;
+ }
+}
+
+/*
+ Memory write. The controller is 16 bit, so we need to demultiplex again.
+*/
+WRITE8_MEMBER(nouspikel_ide_interface_device::write)
+{
+ if (space.debugger_access()) return;
+
+ if (((offset & m_select_mask)==m_select_value) && m_selected)
+ {
+ if (m_cru_register & cru_reg_page_switching)
+ {
+ m_cur_page = (offset >> 1) & PAGE_MASK;
+ }
+
+ int addr = offset & 0x1fff;
+
+ if ((addr <= 0xff) && (m_sram_enable == m_sram_enable_dip))
+ { /* registers */
+ switch ((addr >> 5) & 0x3)
+ {
+ case 0: /* RTC RAM */
+ if (addr & 0x80)
+ /* RTC RAM page register */
+ m_rtc->xram_w(machine().driver_data()->generic_space(),(addr & 0x1f) | 0x20, data);
+ else
+ /* RTC RAM write */
+ m_rtc->xram_w(machine().driver_data()->generic_space(),addr, data);
+ break;
+ case 1: /* RTC registers */
+ if (addr & 0x10)
+ /* register data */
+ m_rtc->rtc_w(machine().driver_data()->generic_space(),1, data);
+ else
+ /* register select */
+ m_rtc->rtc_w(machine().driver_data()->generic_space(),0, data);
+ break;
+ case 2: /* IDE registers set 1 (CS1Fx) */
+/*
+ if (addr & 1)
+ m_output_latch = (m_output_latch & 0xff00) | data;
+ else
+ m_output_latch = (m_output_latch & 0x00ff) | (data << 8);
+*/
+ /* latch write - bytes are swapped in 2004 IDE card */
+ if (addr & 1)
+ m_output_latch = (m_output_latch & 0x00ff) | (data << 8);
+ else
+ m_output_latch = (m_output_latch & 0xff00) | data;
+
+ if (m_tms9995_mode ? (addr & 1) : (!(addr & 1)))
+ { /* second write triggers 16-bit write cycle */
+ m_ata->write_cs0(space, (addr >> 1) & 0x7, m_output_latch, 0xffff);
+ }
+ break;
+ case 3: /* IDE registers set 2 (CS3Fx) */
+/*
+ if (addr & 1)
+ m_output_latch = (m_output_latch & 0xff00) | data;
+ else
+ m_output_latch = (m_output_latch & 0x00ff) | (data << 8);
+*/
+ /* latch write - bytes are swapped in 2004 IDE card */
+ if (addr & 1)
+ m_output_latch = (m_output_latch & 0x00ff) | (data << 8);
+ else
+ m_output_latch = (m_output_latch & 0xff00) | data;
+
+ if (m_tms9995_mode ? (addr & 1) : (!(addr & 1)))
+ { /* second write triggers 16-bit write cycle */
+ m_ata->write_cs1(space, (addr >> 1) & 0x7, m_output_latch, 0xffff);
+ }
+ break;
+ }
+ }
+ else
+ { /* sram */
+ if (! (m_cru_register & cru_reg_wp))
+ {
+ if ((m_cru_register & cru_reg_page_0) || (addr >= 0x1000))
+ m_ram[addr+0x2000 * m_cur_page] = data;
+ else
+ m_ram[addr] = data;
+ }
+ }
+ }
+}
+
+void nouspikel_ide_interface_device::do_inta(int state)
+{
+ m_slot->set_inta(state);
+}
+
+/*
+ ti99_ide_interrupt()
+ IDE interrupt callback
+*/
+WRITE_LINE_MEMBER(nouspikel_ide_interface_device::ide_interrupt_callback)
+{
+ m_ata_irq = state;
+ if (m_cru_register & cru_reg_int_en)
+ do_inta(state);
+}
+
+/*
+ clk_interrupt_callback()
+ clock interrupt callback
+*/
+WRITE_LINE_MEMBER(nouspikel_ide_interface_device::clock_interrupt_callback)
+{
+ m_clk_irq = (state!=0);
+ m_slot->set_inta(state);
+}
+
+void nouspikel_ide_interface_device::device_start()
+{
+ m_rtc = subdevice<rtc65271_device>("ide_rtc");
+
+ m_ram = memregion(BUFFER_TAG)->base();
+ m_sram_enable_dip = false; // TODO: what is this?
+}
+
+void nouspikel_ide_interface_device::device_reset()
+{
+ m_cur_page = 0;
+ m_sram_enable = false;
+ m_cru_register = 0;
+
+ 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("CRUIDE")->read();
+ m_clk_irq = false;
+
+ m_tms9995_mode = false; // (device->type()==TMS9995);
+}
+
+MACHINE_CONFIG_FRAGMENT( tn_ide )
+ MCFG_DEVICE_ADD( "ide_rtc", RTC65271, 0 )
+ MCFG_RTC65271_INTERRUPT_CB(WRITELINE(nouspikel_ide_interface_device, clock_interrupt_callback))
+ MCFG_ATA_INTERFACE_ADD( "ata", ata_devices, "hdd", NULL, false)
+ MCFG_ATA_INTERFACE_IRQ_HANDLER(WRITELINE(nouspikel_ide_interface_device, ide_interrupt_callback))
+MACHINE_CONFIG_END
+
+ROM_START( tn_ide )
+ ROM_REGION(0x80000, BUFFER_TAG, 0) /* RAM buffer 512 KiB */
+ ROM_FILL(0x0000, 0x80000, 0x00)
+ROM_END
+
+INPUT_PORTS_START( tn_ide )
+ PORT_START( "CRUIDE" )
+ PORT_DIPNAME( 0x1f00, 0x1000, "IDE 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" )
+INPUT_PORTS_END
+
+machine_config_constructor nouspikel_ide_interface_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( tn_ide );
+}
+
+const rom_entry *nouspikel_ide_interface_device::device_rom_region() const
+{
+ return ROM_NAME( tn_ide );
+}
+
+ioport_constructor nouspikel_ide_interface_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(tn_ide);
+}
+
+const device_type TI99_IDE = &device_creator<nouspikel_ide_interface_device>;