diff options
Diffstat (limited to 'src/mess/machine/ti99/tn_ide.c')
-rw-r--r-- | src/mess/machine/ti99/tn_ide.c | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/src/mess/machine/ti99/tn_ide.c b/src/mess/machine/ti99/tn_ide.c new file mode 100644 index 00000000000..720f8689cd2 --- /dev/null +++ b/src/mess/machine/ti99/tn_ide.c @@ -0,0 +1,385 @@ +/**************************************************************************** + + 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 have 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/idectrl.h" +#include "tn_ide.h" +#include "ti99_hd.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) +{ + m_shortname = "ti99_ide"; +} + +/* + CRU read +*/ +void nouspikel_ide_interface_device::crureadz(offs_t offset, UINT8 *value) +{ + 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_ide_irq) + reply |= 1; + } + *value = reply; + } +} + +/* + CRU write +*/ +void nouspikel_ide_interface_device::cruwrite(offs_t offset, UINT8 data) +{ + 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_ide_irq); + + if ((bit == 6) || (bit == 7)) + if ((m_cru_register & cru_reg_int_en) && !(m_cru_register & cru_reg_reset)) + m_ide->reset(); + break; + } + } +} + +/* + Memory read +*/ +READ8Z_MEMBER(nouspikel_ide_interface_device::readz) +{ + UINT8 reply = 0; + + 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().memory().first_space(),(addr & 0x1f) | 0x20); + else + /* RTC RAM read */ + reply = m_rtc->xram_r(*machine().memory().first_space(),addr); + break; + case 1: /* RTC registers */ + if (addr & 0x10) + /* register data */ + reply = m_rtc->rtc_r(*machine().memory().first_space(),1); + else + /* register select */ + reply = m_rtc->rtc_r(*machine().memory().first_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)) ? ide_bus_r(m_ide, 0, (addr >> 1) & 0x7) : 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)) ? ide_bus_r(m_ide, 1, (addr >> 1) & 0x7) : 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 (((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().memory().first_space(),(addr & 0x1f) | 0x20, data); + else + /* RTC RAM write */ + m_rtc->xram_w(*machine().memory().first_space(),addr, data); + break; + case 1: /* RTC registers */ + if (addr & 0x10) + /* register data */ + m_rtc->rtc_w(*machine().memory().first_space(),1, data); + else + /* register select */ + m_rtc->rtc_w(*machine().memory().first_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 */ + ide_bus_w(m_ide, 0, (addr >> 1) & 0x7, m_output_latch); + } + 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 */ + ide_bus_w(m_ide, 1, (addr >> 1) & 0x7, m_output_latch); + } + 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 +*/ +static void ide_interrupt_callback(device_t *device, int state) +{ + nouspikel_ide_interface_device *card = downcast<nouspikel_ide_interface_device *>(device->owner()); + card->m_ide_irq = state; + if (card->m_cru_register & cru_reg_int_en) + card->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_ide = subdevice("ide"); + + 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); +} + +static const rtc65271_interface ide_rtc_cfg = +{ + DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, nouspikel_ide_interface_device, clock_interrupt_callback) +}; + +MACHINE_CONFIG_FRAGMENT( tn_ide ) + MCFG_RTC65271_ADD( "ide_rtc", ide_rtc_cfg ) + MCFG_IDE_CONTROLLER_ADD( "ide", ide_interrupt_callback, ide_image_devices, "hdd", NULL, false) // see idectrl.c +// MCFG_IDE_CONTROLLER_REGIONS(":peribox:idehd0:drive", NULL) +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>; + |