From fb9183eb2c0d86c20cff6c80da2e9b9797778de1 Mon Sep 17 00:00:00 2001 From: Michael Zapf Date: Wed, 12 Feb 2014 12:41:40 +0000 Subject: [PATCH] (MESS) Changing to new floppy implementation, part 1. --- src/lib/formats/ti99_dsk.c | 223 +++++++++++++++ src/lib/formats/ti99_dsk.h | 33 +++ src/mess/machine/ti99/peribox.c | 2 + src/mess/machine/ti99/ti_fdc.c | 466 +++++++++++++++++++++++++++++--- src/mess/machine/ti99/ti_fdc.h | 108 +++++++- 5 files changed, 785 insertions(+), 47 deletions(-) diff --git a/src/lib/formats/ti99_dsk.c b/src/lib/formats/ti99_dsk.c index 22bf3d86945..070e59d43c9 100644 --- a/src/lib/formats/ti99_dsk.c +++ b/src/lib/formats/ti99_dsk.c @@ -74,6 +74,7 @@ * always be done. ********************************************************************/ +#include "emu.h" #include #include #include @@ -81,9 +82,231 @@ #include "imageutl.h" #include "ti99_dsk.h" +/* + New format implementation. See below for legacy implementation. +*/ +const char *ti99_sdf_format::name() const +{ + return "sdf"; +} + +const char *ti99_sdf_format::description() const +{ + return "TI99 sector dump floppy disk image"; +} + +const char *ti99_sdf_format::extensions() const +{ + return "dsk"; +} + +bool ti99_sdf_format::supports_save() const +{ + return true; +} + +int ti99_sdf_format::identify(io_generic *io, UINT32 form_factor) +{ + UINT64 file_size = io_generic_size(io); + + // Adding support for another sector image format which adds 768 bytes + // as a bad sector map + if ((file_size / 256) % 10 == 3) + { + logerror("Stripping map of bad sectors at image end\n"); + file_size -= 768; + } + + // Formats with 9 sectors per track + if (((file_size % 92160)==0) + && ( (file_size/92160==1) + || (file_size/92160==2) + || (file_size/92160==4) + || (file_size/92160==8) + || (file_size/92160==16))) return 100; + + // Formats with 16 sectors per track (rare) + if (((file_size % 163840)==0) + && ( (file_size/163840==1) + || (file_size/163840==2))) return 100; + + logerror("Unrecognized disk image geometry\n"); + return 0; +} + +int ti99_sdf_format::find_size(io_generic *io, UINT32 form_factor) +{ + UINT64 file_size = io_generic_size(io); + + // See above + if ((file_size / 256) % 10 == 3) file_size -= 768; + + for (int i=0; formats[i].form_factor != 0; i++) + { + logerror("ti99_dsk: trying size=%d, sec=%d, tr=%d, head=%d, ss=%d\n", (int)file_size, formats[i].sector_count, formats[i].track_count, formats[i].head_count, formats[i].sector_base_size); + if (formats[i].sector_count * formats[i].track_count * formats[i].head_count * formats[i].sector_base_size == (int)file_size) + { + logerror("ti99_dsk: format %d matches\n", i); + return i; + } + } + return -1; +} + +int ti99_sdf_format::get_image_offset(const format &f, int head, int track) +{ + // Note that the logical track arrangement on TI disks is + // + // 00 01 02 03 ... 38 39 side 0 + // 79 78 77 76 ... 41 40 side 1 + // + // and that the SDF format stores the tracks in logical order + // 00 01 02 03 ... 38 39 [40 41 ... 79] + // + int logicaltrack = head * f.track_count; + logicaltrack += ((head&1)==0)? track : (f.track_count - 1 - track); + logerror("ti99_dsk: track %d, head %d -> logical track %d\n", track, head, logicaltrack); + return logicaltrack * compute_track_size(f); +} + +/* + * Common formats: + * 90 KiB = 40 tracks / 1 side / 9 sectors = SSSD + * 180 KiB = 40 tracks / 2 side / 9 sectors = DSSD (most common) + * = 40 tracks / 1 side / 18 sectors = SSDD (rare) + * = 80 tracks / 1 side / 9 sectors = SSSD80 (rare) + * 360 KiB = 40 tracks / 2 side / 18 sectors = DSDD (most common) + * = 80 tracks / 2 side / 9 sectors = DSSD80 (rare) + * = 80 tracks / 1 side / 18 sectors = SSDD80 (rare) + * = 40 tracks / 1 side / 36 sectors = SSHD (rare) + * 720 KiB = 80 tracks / 2 side / 18 sectors = DSDD80 (most common) + * 1440 KiB= 80 tracks / 2 side / 36 sectors = DSHD80 (most common) + * + * Moreover, there may be formats with 35 tracks (ancient) and 8 sectors/track. + * We only check for the 8 sector formats. + * 160 KiB = 40 tracks / 1 side / 16 sectors = SSDD8 + * 320 KiB = 40 tracks / 2 side / 16 sectors = DSDD8 + */ +/* const ti99_sdf_format::file_format ti99_sdf_format::file_formats[] = +{ + { 90, floppy_image::SSSD, 9, 40, 1, 4000 }, // 5.25, 3.5 with double-step + { 160, floppy_image::DSSD, 8, 40, 2, 4000 }, // 5.25, 3.5 with double-step + { 180, floppy_image::DSSD, 9, 40, 2, 4000 }, // 5.25, 3.5 with double-step + { 180, floppy_image::SSDD, 18, 40, 2, 2000 }, // 5.25, 3.5 with double-step + { 320, floppy_image::DSDD, 16, 40, 2, 2000 }, // 5.25, 3.5 with double-step + { 360, floppy_image::DSDD, 18, 40, 2, 2000 }, // 5.25, 3.5 with double-step + { 720, floppy_image::DSDD, 18, 80, 2, 2000 }, // 3.5 + { 1440, floppy_image::DSHD, 36, 80, 2, 1000 }, // 3.5 + { 0, 0, 0, 0, 0, 0 } + // Add more formats with VIB check +}; */ + +// Format: form_factor, variant, encoding, cell_size, sector_count, track_count, +// head_count, sector_base_size, per_sector_size, sector_base_id, +// per_sector_id, gap1, gap2, gap3 + +const ti99_sdf_format::format ti99_sdf_format::formats[] = +{ + { // 90K 5.25" single density single sided + floppy_image::FF_525, floppy_image::SSSD, floppy_image::FM, + 4000, 9, 40, 1, 256, {}, 0, {}, 16, 11, 45 + }, + { // 180K 5.25" single density double sided + floppy_image::FF_525, floppy_image::SSSD, floppy_image::FM, + 4000, 9, 40, 2, 256, {}, 0, {}, 16, 11, 45 + }, + + { 0 } +}; + +/* + * FM track image + */ +floppy_image_format_t::desc_e* ti99_sdf_format::get_desc_fm(const format &f, int ¤t_size, int &end_gap_index) +{ + static floppy_image_format_t::desc_e desc_fm[] = + { + { SECTOR_INTERLEAVE_SKEW, 3, 3 }, // skew/2 because of track*2+head + { FM, 0x00, f.gap_1 }, // Gap 1 (note that we have 00 instead of ff) + { SECTOR_LOOP_START, 0, 8 }, // 9 sectors + { FM, 0x00, 6 }, // pre-id gap + { CRC_CCITT_FM_START, 1 }, + { RAW, 0xf57e, 1 }, // IDAM (fe, clock=c7; 11110101 01111110) + { TRACK_ID_FM }, + { HEAD_ID_FM }, + { SECTOR_ID_FM }, + { SIZE_ID_FM }, + { CRC_END, 1 }, + { CRC, 1 }, + { FM, 0xff, f.gap_2 }, // Gap 2 + { FM, 0x00, 6 }, + { CRC_CCITT_FM_START, 2 }, + { RAW, 0xf56f, 1 }, // DAM (fb, clock=c7; 11110101 01101111) + { SECTOR_DATA_FM, -1 }, // Sector data + { CRC_END, 2 }, + { CRC, 2 }, + { FM, 0xff, f.gap_3 }, // Gap 3 + { SECTOR_LOOP_END }, + { FM, 0xff, 0 }, // track lead-out (end gap, 231) + { END } + }; + current_size = (f.gap_1 + 9 * (6 + 1 + 4 + 2 + f.gap_2 + 6 + 1 + 256 + 2 + f.gap_3) + 0) * 16; + end_gap_index = 21; + + return desc_fm; +} + +/* + * MFM track image + */ +floppy_image_format_t::desc_e* ti99_sdf_format::get_desc_mfm(const format &f, int ¤t_size, int &end_gap_index) +{ + static floppy_image_format_t::desc_e desc_mfm[] = + { + { SECTOR_INTERLEAVE_SKEW, 10, 0 }, + { MFM, 0x4e, 40 }, // track lead-in + { SECTOR_LOOP_START, 0, 17 }, // 18 sectors + { CRC_CCITT_START, 1 }, + { RAW, 0x4489, 3 }, // A1 sync mark + { MFM, 0xfe, 1 }, // IDAM + { TRACK_ID }, + { HEAD_ID }, + { SECTOR_ID }, + { SIZE_ID }, + { CRC_END, 1 }, + { CRC, 1 }, + { MFM, 0x4e, 22 }, // Gap 2 + { MFM, 0x00, 12 }, + { CRC_CCITT_START, 2 }, + { RAW, 0x4489, 3 }, // A1 + { MFM, 0xfb, 1 }, // DAM + { SECTOR_DATA, -1 }, // Sector data + { CRC_END, 2 }, + { CRC, 2 }, + { MFM, 0x4e, 24 }, // Gap 3 + { SECTOR_LOOP_END }, + { MFM, 0x4e, 0 }, // track lead-out (712) + { END } + }; + current_size = (40 + 18 * (3 + 1 + 4 + 2 + 22 + 12 + 3 + 1 + 256 + 2 + 24) + 0) * 16; + end_gap_index = 22; + + return desc_mfm; +} + +const floppy_format_type FLOPPY_TI99_SDF_FORMAT = &floppy_image_format_creator; + +//========================================================================== #define SECTOR_SIZE 256 #define TI99_IDAM_LENGTH 7 + +/************************************************************** + + Legacy implementation + +**************************************************************/ + /* Determines whether we are using 80 track drives. This variable is necessary unless we get information about the dip diff --git a/src/lib/formats/ti99_dsk.h b/src/lib/formats/ti99_dsk.h index 55612c6123a..4643bc88ec8 100644 --- a/src/lib/formats/ti99_dsk.h +++ b/src/lib/formats/ti99_dsk.h @@ -11,9 +11,42 @@ #define TI99_DSK_H #include "flopimg.h" +#include "wd177x_dsk.h" + +/* + New implementation. + TDF format still to be done; + also, this implementation just considers FM for now. +*/ +class ti99_sdf_format : public wd177x_format +{ +public: + ti99_sdf_format(): wd177x_format(formats) { } + + int identify(io_generic *io, UINT32 form_factor); + + const char *name() const; + const char *description() const; + const char *extensions() const; + bool supports_save() const; + +private: + static const format formats[]; + floppy_image_format_t::desc_e* get_desc_fm(const format &f, int ¤t_size, int &end_gap_index); + floppy_image_format_t::desc_e* get_desc_mfm(const format &f, int ¤t_size, int &end_gap_index); + + int get_format_param(io_generic *io); + int get_image_offset(const format &f, int head, int track); + int find_size(io_generic *io, UINT32 form_factor); +}; + +/* + Legacy implementation. +*/ LEGACY_FLOPPY_OPTIONS_EXTERN(ti99); void ti99_set_80_track_drives(int use80); +extern const floppy_format_type FLOPPY_TI99_SDF_FORMAT; #endif /* TI99_DSK_H */ diff --git a/src/mess/machine/ti99/peribox.c b/src/mess/machine/ti99/peribox.c index dc0de785cd9..36c8a0daaff 100644 --- a/src/mess/machine/ti99/peribox.c +++ b/src/mess/machine/ti99/peribox.c @@ -418,6 +418,7 @@ SLOT_INTERFACE_START( peribox_slot7 ) SLOT_INTERFACE_END SLOT_INTERFACE_START( peribox_slot8 ) + SLOT_INTERFACE("tifdcleg", TI99_FDC_LEG) SLOT_INTERFACE("tifdc", TI99_FDC) SLOT_INTERFACE("bwg", TI99_BWG) SLOT_INTERFACE("hfdc", TI99_HFDC) @@ -462,6 +463,7 @@ SLOT_INTERFACE_START( peribox_slot7nobwg ) SLOT_INTERFACE_END SLOT_INTERFACE_START( peribox_slot8nobwg ) + SLOT_INTERFACE("tifdcleg", TI99_FDC_LEG) SLOT_INTERFACE("tifdc", TI99_FDC) SLOT_INTERFACE("hfdc", TI99_HFDC) SLOT_INTERFACE_END diff --git a/src/mess/machine/ti99/ti_fdc.c b/src/mess/machine/ti99/ti_fdc.c index 5dbdc76c319..187145b46c1 100644 --- a/src/mess/machine/ti99/ti_fdc.c +++ b/src/mess/machine/ti99/ti_fdc.c @@ -42,39 +42,22 @@ #define TRACE_MOTOR 0 // ---------------------------------- - -#define TI_FDC_TAG "ti_dssd_controller" - -#define FDC_TAG "wd1771" - +#define FDC_TAG "fd1771" #define MOTOR_TIMER 1 -const wd17xx_interface ti_wd17xx_interface = -{ - DEVCB_NULL, - DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_fdc_device, intrq_w), - DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_fdc_device, drq_w), - { PFLOPPY_0, PFLOPPY_1, PFLOPPY_2, NULL } -}; +#define TI_FDC_TAG "ti_dssd_controller" +#define FLOPPY_FORMATS_END_NO_DEFAULTS ,\ + NULL }; + ti_fdc_device::ti_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : ti_expansion_card_device(mconfig, TI99_FDC, "TI-99 Standard DSSD Floppy Controller", tag, owner, clock, "ti99_fdc", __FILE__), m_fd1771(*this, FDC_TAG) { } -/* - callback called at the end of DVENA pulse -*/ -void ti_fdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - m_DVENA = CLEAR_LINE; - if (TRACE_MOTOR) logerror("tifdc: Motor off\n"); - set_ready_line(); -} - /* Operate the wait state logic. */ -void ti_fdc_device::set_ready_line() +void ti_fdc_device::operate_ready_line() { // This is the wait state logic if (TRACE_SIGNALS) logerror("tifdc: address=%04x, DRQ=%d, INTRQ=%d, MOTOR=%d\n", m_address & 0xffff, m_DRQ, m_IRQ, m_DVENA); @@ -89,6 +72,29 @@ void ti_fdc_device::set_ready_line() m_slot->set_ready((nready==CLEAR_LINE)? ASSERT_LINE : CLEAR_LINE); } +/* + * Callbacks from the FD1771 chip + */ +void ti_fdc_device::irq_w(bool state) +{ + m_IRQ = state? ASSERT_LINE : CLEAR_LINE; + if (TRACE_SIGNALS) logerror("tifdc: INTRQ callback = %d\n", m_IRQ); + operate_ready_line(); +} + +void ti_fdc_device::drq_w(bool state) +{ + m_DRQ = state? ASSERT_LINE : CLEAR_LINE; + if (TRACE_SIGNALS) logerror("tifdc: DRQ callback = %d\n", m_DRQ); + operate_ready_line(); +} + +// bool ti_fdc_device::dvena_r() +// { +// if (TRACE_SIGNALS) logerror("tifdc: reading DVENA = %d\n", m_DVENA); +// return (m_DVENA==ASSERT_LINE); +// } + SETADDRESS_DBIN_MEMBER( ti_fdc_device::setaddress_dbin ) { // Selection login in the PAL and some circuits on the board @@ -97,6 +103,378 @@ SETADDRESS_DBIN_MEMBER( ti_fdc_device::setaddress_dbin ) m_address = offset; m_inDsrArea = ((m_address & m_select_mask)==m_select_value); + if (!m_inDsrArea || !m_selected) return; + + if (TRACE_ADDRESS) logerror("tifdc: set address = %04x\n", offset & 0xffff); + + // Is the WD chip on the card being selected? + m_WDsel = m_inDsrArea && ((m_address & 0x1ff1)==0x1ff0); + + // Clear or assert the outgoing READY line + operate_ready_line(); +} + +READ8Z_MEMBER(ti_fdc_device::readz) +{ + if (m_inDsrArea && m_selected) + { + // Read ports of 1771 are mapped to 5FF0,2,4,6: 0101 1111 1111 0xx0 + // Note that incoming/outgoing data are inverted for FD1771 + UINT8 reply = 0; + + if (m_WDsel && ((m_address & 9)==0)) + { + if (!space.debugger_access()) reply = m_fd1771->gen_r((offset >> 1)&0x03); + if (TRACE_DATA) + { + if ((m_address & 0xffff)==0x5ff6) + { + if (!m_debug_dataout) logerror("tifdc: Read data = "); + m_debug_dataout = true; + logerror("%02x ", ~reply & 0xff); + } + else + { + if (m_debug_dataout) logerror("\n"); + m_debug_dataout = false; + } + } + } + else + { + reply = m_dsrrom[m_address & 0x1fff]; + } + *value = reply; + if (TRACE_RW) logerror("tifdc: %04x -> %02x\n", offset & 0xffff, *value); + } +} + +WRITE8_MEMBER(ti_fdc_device::write) +{ + if (m_inDsrArea && m_selected) + { + // Write ports of 1771 are mapped to 5FF8,A,C,E: 0101 1111 1111 1xx0 + // This is important for the TI console: The TMS9900 CPU always performs a + // read operation before the write operation, and if we did not use + // different read and write ports, it would attempt to read from the + // controller before passing a command or data + // to it. In the best case, nothing happens; in the worst case, status + // flags may be reset by the read operation. + + // Note that incoming/outgoing data are inverted for FD1771 + if (TRACE_RW) logerror("tifdc: %04x <- %02x\n", offset & 0xffff, ~data & 0xff); + if (m_WDsel && ((m_address & 9)==8)) + { + // As this is a memory-mapped access we must prevent the debugger + // from messing with the operation + if (!space.debugger_access()) m_fd1771->gen_w((offset >> 1)&0x03, data); + } + } +} + +/* + CRU read access + + 7 6 5 4 3 2 1 0 + +-----+-----+-----+------+-----+-----+-----+-----+ + | Side| 1 | 0 |DVENA*| DSK3| DSK2| DSK1| HLD | + +-----+-----+-----+------+-----+-----+-----+-----+ + + We have only 8 bits for query; within this implementation this means + we only use the base address (offset 0). +*/ +READ8Z_MEMBER(ti_fdc_device::crureadz) +{ + if ((offset & 0xff00)==m_cru_base) + { + UINT8 reply = 0; + if ((offset & 0x07) == 0) + { + // Selected drive + reply |= ((m_DSEL)<<1); + // The DVENA state is returned as inverted + if (m_DVENA==CLEAR_LINE) reply |= 0x10; + // Always 1 + reply |= 0x40; + // Selected side + if (m_SIDSEL==ASSERT_LINE) reply |= 0x80; + } + *value = reply; + if (TRACE_CRU) logerror("tifdc: Read CRU = %02x\n", *value); + } +} + +WRITE8_MEMBER(ti_fdc_device::cruwrite) +{ + if ((offset & 0xff00)==m_cru_base) + { + int bit = (offset >> 1) & 0x07; + switch (bit) + { + case 0: + // (De)select the card. Indicated by a LED on the board. + m_selected = (data!=0); + if (TRACE_CRU) logerror("tifdc: Map DSR (bit 0) = %d\n", m_selected); + break; + + case 1: + // Activate motor + if (data==1 && m_lastval==0) + { // On rising edge, set motor_running for 4.23s + if (TRACE_CRU) logerror("tifdc: trigger motor (bit 1)\n"); + set_floppy_motors_running(true); + m_motor_on_timer->adjust(attotime::from_msec(4230)); + } + m_lastval = data; + break; + + case 2: + // Set disk ready/hold (bit 2) + // 0: ignore IRQ and DRQ + // 1: TMS9900 is stopped until IRQ or DRQ are set + // OR the motor stops rotating - rotates for 4.23s after write + // to CRU bit 1 + m_WAITena = (data != 0); + if (TRACE_CRU) logerror("tifdc: arm wait state logic (bit 2) = %d\n", data); + break; + + case 3: + // Load disk heads (HLT pin) (bit 3). Not implemented. + if (TRACE_CRU) logerror("tifdc: set head load (bit 3) = %d\n", data); + break; + + case 4: + m_DSEL = (data != 0)? (m_DSEL | 0x01) : (m_DSEL & 0xfe); + set_drive(); + break; + case 5: + m_DSEL = (data != 0)? (m_DSEL | 0x02) : (m_DSEL & 0xfd); + set_drive(); + break; + case 6: + m_DSEL = (data != 0)? (m_DSEL | 0x04) : (m_DSEL & 0xfb); + set_drive(); + break; + + case 7: + // Select side of disk (bit 7) + m_SIDSEL = (data==1)? ASSERT_LINE : CLEAR_LINE; + if (TRACE_CRU) logerror("tifdc: set side (bit 7) = %d\n", data); + if (m_current_floppy != NULL) m_current_floppy->ss_w(data); + break; + + default: + break; + } + } +} + +void ti_fdc_device::set_drive() +{ + int i = -1; + switch (m_DSEL) + { + case 0: + m_current_floppy = NULL; + if (TRACE_CRU) logerror("tifdc: all drives deselected\n"); + break; + case 1: + i = 0; + break; + case 2: + i = 1; + break; + case 3: + // The schematics do not reveal any countermeasures against multiple selection + // so we assume that the highest value wins. + i = 1; + logerror("tifdc: Warning - multiple drives selected\n"); + break; + case 4: + i = 2; + break; + default: + i = 2; + logerror("tifdc: Warning - multiple drives selected\n"); + break; + } + if (TRACE_CRU) logerror("tifdc: new DSEL = %d\n", m_DSEL); + if (i != -1) m_current_floppy = m_floppy[i]; + + m_fd1771->set_floppy(m_current_floppy); +} + +/* + Monoflop has gone back to the OFF state. +*/ +void ti_fdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + set_floppy_motors_running(false); +} + +/* + All floppy motors are operated by the same line. +*/ +void ti_fdc_device::set_floppy_motors_running(bool run) +{ + if (TRACE_MOTOR) + { + if (m_DVENA==ASSERT_LINE && !run) logerror("tifdc: Motor STOP\n"); + if (m_DVENA==CLEAR_LINE && run) logerror("tifdc: Motor START\n"); + } + m_DVENA = (run)? ASSERT_LINE : CLEAR_LINE; + m_fd1771->set_force_ready(run); + + for (int i=0; i < 3; i++) + if (m_floppy[i] != NULL) m_floppy[i]->mon_w((run)? 0 : 1); + operate_ready_line(); +} + +void ti_fdc_device::device_start() +{ + logerror("tifdc: TI FDC start\n"); + m_dsrrom = memregion(DSRROM)->base(); + m_motor_on_timer = timer_alloc(MOTOR_TIMER); + m_cru_base = 0x1100; + m_fd1771->setup_intrq_cb(wd_fdc_t::line_cb(FUNC(ti_fdc_device::irq_w), this)); + m_fd1771->setup_drq_cb(wd_fdc_t::line_cb(FUNC(ti_fdc_device::drq_w), this)); + // In case we implement a callback after all: + // m_fd1771->setup_ready_cb(wd_fdc_t::rline_cb(FUNC(ti_fdc_device::dvena_r), this)); +} + +void ti_fdc_device::device_reset() +{ + logerror("tifdc: TI FDC reset\n"); + m_lastval = 0; + if (m_genmod) + { + m_select_mask = 0x1fe000; + m_select_value = 0x174000; + } + else + { + m_select_mask = 0x7e000; + m_select_value = 0x74000; + } + m_DRQ = CLEAR_LINE; + m_IRQ = CLEAR_LINE; + m_DVENA = CLEAR_LINE; + m_fd1771->set_force_ready(false); + + m_DSEL = 0; + m_WAITena = false; + m_selected = false; + m_debug_dataout = false; + + for (int i=0; i < 3; i++) + { + if (m_floppy[i] != NULL) + logerror("tifdc: Connector %d with %s\n", i, m_floppy[i]->name()); + else + logerror("tifdc: No floppy attached to connector %d\n", i); + } + + m_fd1771->set_floppy(m_current_floppy = m_floppy[0]); +} + +void ti_fdc_device::device_config_complete() +{ + // Seems to be null when doing a "-listslots" + if (subdevice("0")!=NULL) m_floppy[0] = static_cast(subdevice("0")->first_subdevice()); + if (subdevice("1")!=NULL) m_floppy[1] = static_cast(subdevice("1")->first_subdevice()); + if (subdevice("2")!=NULL) m_floppy[2] = static_cast(subdevice("2")->first_subdevice()); +} + +FLOPPY_FORMATS_MEMBER(ti_fdc_device::floppy_formats) + FLOPPY_TI99_SDF_FORMAT +FLOPPY_FORMATS_END_NO_DEFAULTS + +static SLOT_INTERFACE_START( tifdc_floppies ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) +SLOT_INTERFACE_END + +MACHINE_CONFIG_FRAGMENT( ti_fdc ) + MCFG_FD1771x_ADD(FDC_TAG, XTAL_1MHz) + MCFG_FLOPPY_DRIVE_ADD("0", tifdc_floppies, "525dd", ti_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("1", tifdc_floppies, NULL, ti_fdc_device::floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("2", tifdc_floppies, NULL, ti_fdc_device::floppy_formats) +MACHINE_CONFIG_END + +ROM_START( ti_fdc ) + ROM_REGION(0x2000, DSRROM, 0) + ROM_LOAD("disk.bin", 0x0000, 0x2000, CRC(8f7df93f) SHA1(ed91d48c1eaa8ca37d5055bcf67127ea51c4cad5)) /* TI disk DSR ROM */ +ROM_END + +machine_config_constructor ti_fdc_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( ti_fdc ); +} + +const rom_entry *ti_fdc_device::device_rom_region() const +{ + return ROM_NAME( ti_fdc ); +} + +const device_type TI99_FDC = &device_creator; +//=========================================================================== + +/*********************************************** + + Legacy implementation, to be removed + +***********************************************/ + +#define TI_FDCLEG_TAG "ti_dssd_controller_legacy" +#define FDCLEG_TAG "wd1771" + +const wd17xx_interface ti_wd17xx_interface = +{ + DEVCB_NULL, + DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_fdc_legacy_device, intrq_w), + DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ti_fdc_legacy_device, drq_w), + { PFLOPPY_0, PFLOPPY_1, PFLOPPY_2, NULL } +}; + +ti_fdc_legacy_device::ti_fdc_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ti_expansion_card_device(mconfig, TI99_FDC_LEG, "TI-99 Standard DSSD Floppy Controller (legacy)", tag, owner, clock, "ti99_fdc", __FILE__), + m_fd1771(*this, FDCLEG_TAG) { } + +/* + callback called at the end of DVENA pulse +*/ +void ti_fdc_legacy_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + m_DVENA = CLEAR_LINE; + if (TRACE_MOTOR) logerror("tifdc: Motor off\n"); + set_ready_line(); +} + +/* + Operate the wait state logic. +*/ +void ti_fdc_legacy_device::set_ready_line() +{ + // This is the wait state logic + if (TRACE_SIGNALS) logerror("tifdc: address=%04x, DRQ=%d, INTRQ=%d, MOTOR=%d\n", m_address & 0xffff, m_DRQ, m_IRQ, m_DVENA); + line_state nready = (m_WDsel && // Are we accessing 5ffx (even addr)? + m_WAITena && // and the wait state generation is active (SBO 2) + (m_DRQ==CLEAR_LINE) && // and we are waiting for a byte + (m_IRQ==CLEAR_LINE) && // and there is no interrupt yet + (m_DVENA==ASSERT_LINE) // and the motor is turning? + )? ASSERT_LINE : CLEAR_LINE; // In that case, clear READY and thus trigger wait states + + if (TRACE_READY) logerror("tifdc: READY line = %d\n", (nready==CLEAR_LINE)? 1:0); + m_slot->set_ready((nready==CLEAR_LINE)? ASSERT_LINE : CLEAR_LINE); +} + +SETADDRESS_DBIN_MEMBER( ti_fdc_legacy_device::setaddress_dbin ) +{ + // Selection login in the PAL and some circuits on the board + + // Is the card being selected? + m_address = offset; + m_inDsrArea = ((m_address & m_select_mask)==m_select_value); + if (!m_inDsrArea) return; if (TRACE_ADDRESS) logerror("tifdc: set address = %04x\n", offset & 0xffff); @@ -108,7 +486,7 @@ SETADDRESS_DBIN_MEMBER( ti_fdc_device::setaddress_dbin ) set_ready_line(); } -READ8Z_MEMBER(ti_fdc_device::readz) +READ8Z_MEMBER(ti_fdc_legacy_device::readz) { if (m_inDsrArea && m_selected) { @@ -117,7 +495,7 @@ READ8Z_MEMBER(ti_fdc_device::readz) // 0101 1111 1111 0xx0 UINT8 reply = 0; - if (m_WDsel && ((m_address & 1)==0)) + if (m_WDsel && ((m_address & 9)==0)) { if (!space.debugger_access()) reply = wd17xx_r(m_fd1771, space, (offset >> 1)&0x03); if (TRACE_DATA) @@ -135,7 +513,7 @@ READ8Z_MEMBER(ti_fdc_device::readz) } } -WRITE8_MEMBER(ti_fdc_device::write) +WRITE8_MEMBER(ti_fdc_legacy_device::write) { if (m_inDsrArea && m_selected) { @@ -159,7 +537,7 @@ WRITE8_MEMBER(ti_fdc_device::write) bit 6: always 1 bit 7: selected side */ -READ8Z_MEMBER(ti_fdc_device::crureadz) +READ8Z_MEMBER(ti_fdc_legacy_device::crureadz) { if ((offset & 0xff00)==m_cru_base) { @@ -180,7 +558,7 @@ READ8Z_MEMBER(ti_fdc_device::crureadz) } } -WRITE8_MEMBER(ti_fdc_device::cruwrite) +WRITE8_MEMBER(ti_fdc_legacy_device::cruwrite) { int drive, drivebit; @@ -259,7 +637,7 @@ WRITE8_MEMBER(ti_fdc_device::cruwrite) the default implementation sets the drive geometry to the geometry of the medium. */ -void ti_fdc_device::set_geometry(device_t *drive, floppy_type_t type) +void ti_fdc_legacy_device::set_geometry(device_t *drive, floppy_type_t type) { // This assertion may fail when the names of the floppy devices change. // Unfortunately, the wd17xx device assumes the floppy drives at root @@ -268,7 +646,7 @@ void ti_fdc_device::set_geometry(device_t *drive, floppy_type_t type) floppy_drive_set_geometry(drive, type); } -void ti_fdc_device::set_all_geometries(floppy_type_t type) +void ti_fdc_legacy_device::set_all_geometries(floppy_type_t type) { set_geometry(machine().device(PFLOPPY_0), type); set_geometry(machine().device(PFLOPPY_1), type); @@ -278,7 +656,7 @@ void ti_fdc_device::set_all_geometries(floppy_type_t type) /* Callback, called from the controller chip whenever DRQ/IRQ state change */ -WRITE_LINE_MEMBER( ti_fdc_device::intrq_w ) +WRITE_LINE_MEMBER( ti_fdc_legacy_device::intrq_w ) { if (TRACE_SIGNALS) logerror("ti_fdc: set irq = %d\n", state); m_IRQ = (line_state)state; @@ -289,24 +667,24 @@ WRITE_LINE_MEMBER( ti_fdc_device::intrq_w ) set_ready_line(); } -WRITE_LINE_MEMBER( ti_fdc_device::drq_w ) +WRITE_LINE_MEMBER( ti_fdc_legacy_device::drq_w ) { if (TRACE_SIGNALS) logerror("ti_fdc: set drq = %d\n", state); m_DRQ = (line_state)state; set_ready_line(); } -void ti_fdc_device::device_start(void) +void ti_fdc_legacy_device::device_start(void) { - logerror("ti_fdc: TI FDC start\n"); + logerror("ti_fdc: TI FDC (legacy) start\n"); m_dsrrom = memregion(DSRROM)->base(); m_motor_on_timer = timer_alloc(MOTOR_TIMER); m_cru_base = 0x1100; } -void ti_fdc_device::device_reset(void) +void ti_fdc_legacy_device::device_reset(void) { - logerror("ti_fdc: TI FDC reset\n"); + logerror("ti_fdc: TI FDC (legacy) reset\n"); m_DSEL = 0; m_SIDSEL = 0; m_DVENA = CLEAR_LINE; @@ -331,23 +709,23 @@ void ti_fdc_device::device_reset(void) set_all_geometries(type); } -MACHINE_CONFIG_FRAGMENT( ti_fdc ) - MCFG_FD1771_ADD(FDC_TAG, ti_wd17xx_interface ) +MACHINE_CONFIG_FRAGMENT( ti_fdc_legacy ) + MCFG_FD1771_ADD(FDCLEG_TAG, ti_wd17xx_interface ) MACHINE_CONFIG_END -ROM_START( ti_fdc ) +ROM_START( ti_fdc_legacy ) ROM_REGION(0x2000, DSRROM, 0) ROM_LOAD("disk.bin", 0x0000, 0x2000, CRC(8f7df93f) SHA1(ed91d48c1eaa8ca37d5055bcf67127ea51c4cad5)) /* TI disk DSR ROM */ ROM_END -machine_config_constructor ti_fdc_device::device_mconfig_additions() const +machine_config_constructor ti_fdc_legacy_device::device_mconfig_additions() const { - return MACHINE_CONFIG_NAME( ti_fdc ); + return MACHINE_CONFIG_NAME( ti_fdc_legacy ); } -const rom_entry *ti_fdc_device::device_rom_region() const +const rom_entry *ti_fdc_legacy_device::device_rom_region() const { - return ROM_NAME( ti_fdc ); + return ROM_NAME( ti_fdc_legacy ); } -const device_type TI99_FDC = &device_creator; +const device_type TI99_FDC_LEG = &device_creator; diff --git a/src/mess/machine/ti99/ti_fdc.h b/src/mess/machine/ti99/ti_fdc.h index a733487838d..06ef8ee8492 100644 --- a/src/mess/machine/ti99/ti_fdc.h +++ b/src/mess/machine/ti99/ti_fdc.h @@ -11,13 +11,12 @@ January 2012: rewritten as class (MZ) ****************************************************************************/ - #ifndef __TIFDC__ #define __TIFDC__ #include "ti99defs.h" -#include "machine/wd17xx.h" -#include "imagedev/flopdrv.h" +#include "machine/wd_fdc.h" +#include "imagedev/floppy.h" extern const device_type TI99_FDC; @@ -35,6 +34,109 @@ public: DECLARE_READ8Z_MEMBER(crureadz); DECLARE_WRITE8_MEMBER(cruwrite); + DECLARE_FLOPPY_FORMATS( floppy_formats ); + + void irq_w(bool state); + void drq_w(bool state); + // bool dvena_r(); + +protected: + void device_start(); + void device_reset(); + void device_config_complete(); + + const rom_entry *device_rom_region() const; + machine_config_constructor device_mconfig_additions() const; + + void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + // Wait state logic + void operate_ready_line(); + + // Set the current floppy + void set_drive(); + + // Operate the floppy motors + void set_floppy_motors_running(bool run); + + // Recent address + int m_address; + + // Holds the status of the DRQ and IRQ lines. + line_state m_DRQ, m_IRQ; + + // Needed for triggering the motor monoflop + UINT8 m_lastval; + + // Signal DVENA. When TRUE, makes some drive turning. + line_state m_DVENA; + + // Set when address is in card area + bool m_inDsrArea; + + // When TRUE the CPU is halted while DRQ/IRQ are true. + bool m_WAITena; + + // WD chip selected + bool m_WDsel; + + // Indicates which drive has been selected. Values are 0, 1, 2, and 4. + // 000 = no drive + // 001 = drive 1 + // 010 = drive 2 + // 100 = drive 3 + int m_DSEL; + + // Signal SIDSEL. 0 or 1, indicates the selected head. + line_state m_SIDSEL; + + // count 4.23s from rising edge of motor_on + emu_timer* m_motor_on_timer; + + // Link to the FDC1771 controller on the board. + required_device m_fd1771; + + // DSR ROM + UINT8* m_dsrrom; + + // Link to the attached floppy drives + floppy_image_device* m_floppy[3]; + + // Currently selected floppy drive + floppy_image_device* m_current_floppy; + + // Debugging + bool m_debug_dataout; +}; + +//=========================================================================== + +/*********************************************** + + Legacy implementation + +***********************************************/ + +#include "machine/wd17xx.h" +#include "imagedev/flopdrv.h" + +extern const device_type TI99_FDC_LEG; + +class ti_fdc_legacy_device : public ti_expansion_card_device +{ +public: + ti_fdc_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + DECLARE_READ8Z_MEMBER(readz); + DECLARE_WRITE8_MEMBER(write); + DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin); + + DECLARE_WRITE_LINE_MEMBER( intrq_w ); + DECLARE_WRITE_LINE_MEMBER( drq_w ); + + DECLARE_READ8Z_MEMBER(crureadz); + DECLARE_WRITE8_MEMBER(cruwrite); + protected: virtual void device_start(void); virtual void device_reset(void);