diff options
author | 2012-10-10 15:33:51 +0000 | |
---|---|---|
committer | 2012-10-10 15:33:51 +0000 | |
commit | 9d1aaf97ae5a4d5b2272f064fe6b6fe7df9dbf88 (patch) | |
tree | 74e3dc1e5558b42717e62f9b81cc7d7d47b90449 /src/mess/machine | |
parent | 204b78cf00de0c3bd8b6afefa601cd26aa391c91 (diff) |
(mess) upd765: Modernize [O. Galibert]
Remaining TODO list:
- take WP into account
- test the amstrad, implement its observational format (edsk) using
pasti as a start. Or find the legendary amstrad IPFs. Or both.
- correct read track, the implementation is completely wrong. See
previous for testing, it's only used in protections the check the
inter-sector gaps.
- shake and bake on the amstrad, protections are the best to find bugs
in a fdc
- add the scan id commands, but nothing seems to use them
- debug the 2.88M formatting which is unreliable. Fix its IDAM/DAM
gap size on formatting too (but that's not what's making it
unreliable)
- test all the systems that were hit, and fix what needs to be fixed.
Beware that multiple problems may happen:
- upd765 may be wrong
- the driver may not be working
- the hookup may be wrong/incomplete (bitrate selection and floppy
rpm in particular)
- the driver may be too limited for the new implementation (the x68k
dma device does not handle non-instant dma yet for instance)
- report invalid command when appropriate depending on the actual chip
emulated
- add the russian clones with their real names
Diffstat (limited to 'src/mess/machine')
-rw-r--r-- | src/mess/machine/amstrad.c | 42 | ||||
-rw-r--r-- | src/mess/machine/apollo.c | 102 | ||||
-rw-r--r-- | src/mess/machine/bebox.c | 69 | ||||
-rw-r--r-- | src/mess/machine/compis.c | 71 | ||||
-rw-r--r-- | src/mess/machine/fd2000.c | 46 | ||||
-rw-r--r-- | src/mess/machine/fd2000.h | 2 | ||||
-rw-r--r-- | src/mess/machine/genpc.c | 4 | ||||
-rw-r--r-- | src/mess/machine/hec2hrp.c | 7 | ||||
-rw-r--r-- | src/mess/machine/hecdisk2.c | 205 | ||||
-rw-r--r-- | src/mess/machine/iq151_disc2.c | 49 | ||||
-rw-r--r-- | src/mess/machine/iq151_disc2.h | 3 | ||||
-rw-r--r-- | src/mess/machine/isa.h | 3 | ||||
-rw-r--r-- | src/mess/machine/isa_fdc.c | 483 | ||||
-rw-r--r-- | src/mess/machine/isa_fdc.h | 88 | ||||
-rw-r--r-- | src/mess/machine/kc_d004.c | 98 | ||||
-rw-r--r-- | src/mess/machine/kc_d004.h | 11 | ||||
-rw-r--r-- | src/mess/machine/n82077aa.c | 1212 | ||||
-rw-r--r-- | src/mess/machine/n82077aa.h | 203 | ||||
-rw-r--r-- | src/mess/machine/pc.c | 50 | ||||
-rw-r--r-- | src/mess/machine/pc_fdc.c | 194 | ||||
-rw-r--r-- | src/mess/machine/pc_fdc.h | 79 | ||||
-rw-r--r-- | src/mess/machine/pf10.c | 11 | ||||
-rw-r--r-- | src/mess/machine/tf20.c | 72 | ||||
-rw-r--r-- | src/mess/machine/upd765.c | 3887 | ||||
-rw-r--r-- | src/mess/machine/upd765.h | 557 |
25 files changed, 2715 insertions, 4833 deletions
diff --git a/src/mess/machine/amstrad.c b/src/mess/machine/amstrad.c index 14b9dbfeb2a..7ff1af47572 100644 --- a/src/mess/machine/amstrad.c +++ b/src/mess/machine/amstrad.c @@ -215,12 +215,9 @@ PALETTE_INIT_MEMBER(amstrad_state,amstrad_cpc_green) } -WRITE_LINE_MEMBER(amstrad_state::aleste_interrupt) +void amstrad_state::aleste_interrupt(bool state) { - if(state == CLEAR_LINE) - m_aleste_fdc_int = 0; - else - m_aleste_fdc_int = 1; + m_aleste_fdc_int = state; } @@ -1857,7 +1854,6 @@ Expansion Peripherals Read/Write - - - - - 0 - - - - - - READ8_MEMBER(amstrad_state::amstrad_cpc_io_r) { - device_t *fdc = m_fdc; mc6845_device *mc6845 = m_crtc; unsigned char data = 0xFF; @@ -1951,10 +1947,10 @@ The exception is the case where none of b7-b0 are reset (i.e. port &FBFF), which switch (b8b0) { case 0x02: - data = upd765_status_r(fdc, space, 0); + data = m_fdc->msr_r(space, 0); break; case 0x03: - data = upd765_data_r(fdc, space, 0); + data = m_fdc->fifo_r(space, 0); break; default: break; @@ -1993,7 +1989,6 @@ void amstrad_state::amstrad_plus_seqcheck(int data) /* Offset handler for write */ WRITE8_MEMBER(amstrad_state::amstrad_cpc_io_w) { - device_t *fdc = m_fdc; mc6845_device *mc6845 = m_crtc; cpc_multiface2_device* mface2; @@ -2118,18 +2113,22 @@ The exception is the case where none of b7-b0 are reset (i.e. port &FBFF), which switch (b8b0) { - case 0x00: + case 0x00: { /* FDC Motor Control - Bit 0 defines the state of the FDD motor: * "1" the FDD motor will be active. * "0" the FDD motor will be in-active.*/ - floppy_mon_w(floppy_get_device(machine(), 0), !BIT(data, 0)); - floppy_mon_w(floppy_get_device(machine(), 1), !BIT(data, 0)); - floppy_drive_set_ready_state(floppy_get_device(machine(), 0), 1,1); - floppy_drive_set_ready_state(floppy_get_device(machine(), 1), 1,1); + floppy_image_device *floppy; + floppy = machine().device<floppy_connector>(":upd765a:0")->get_device(); + if(floppy) + floppy->mon_w(!BIT(data, 0)); + floppy = machine().device<floppy_connector>(":upd765a:1")->get_device(); + if(floppy) + floppy->mon_w(!BIT(data, 0)); break; + } case 0x03: /* Write Data register of FDC */ - upd765_data_w(fdc, space, 0,data); + m_fdc->fifo_w(space, 0,data); break; default: @@ -3267,16 +3266,3 @@ DEVICE_IMAGE_LOAD(amstrad_plus_cartridge) auto_free(image.device().machine(), temp_copy); return IMAGE_INIT_PASS; } - - -#if 0 -static DEVICE_IMAGE_LOAD( aleste ) -{ - if (device_load_basicdsk_floppy(image)==IMAGE_INIT_PASS) - { - basicdsk_set_geometry(image, 80, 2, 9, 512, 0x01, 0, FALSE); - return IMAGE_INIT_PASS; - } - return IMAGE_INIT_FAIL; -} -#endif diff --git a/src/mess/machine/apollo.c b/src/mess/machine/apollo.c index a30c2660b0c..137ae523471 100644 --- a/src/mess/machine/apollo.c +++ b/src/mess/machine/apollo.c @@ -37,7 +37,8 @@ #include "machine/pic8259.h" #include "machine/pc_fdc.h" -#include "formats/basicdsk.h" +#include "formats/mfi_dsk.h" +#include "formats/apollo_dsk.h" #include "cpu/m68000/m68000.h" //#include "cpu/m68000/m68kcpu.h" @@ -526,7 +527,8 @@ static WRITE8_DEVICE_HANDLER( apollo_dma8237_ctape_dack_w ) { } static READ8_DEVICE_HANDLER( apollo_dma8237_fdc_dack_r ) { - UINT8 data = pc_fdc_dack_r(space.machine(), space); + pc_fdc_at_device *fdc = space.machine().device<pc_fdc_at_device>(APOLLO_FDC_TAG); + UINT8 data = fdc->dma_r(); // DLOG2(("dma fdc dack read %02x",data)); // hack for DN3000: select appropriate DMA channel No. @@ -536,8 +538,9 @@ static READ8_DEVICE_HANDLER( apollo_dma8237_fdc_dack_r ) { } static WRITE8_DEVICE_HANDLER( apollo_dma8237_fdc_dack_w ) { + pc_fdc_at_device *fdc = space.machine().device<pc_fdc_at_device>(APOLLO_FDC_TAG); // DLOG2(("dma fdc dack write %02x", data)); - pc_fdc_dack_w(space.machine(), space, data); + fdc->dma_w(data); // hack for DN3000: select appropriate DMA channel No. // Note: too late for this byte, but next bytes will be ok @@ -556,8 +559,9 @@ static WRITE8_DEVICE_HANDLER( apollo_dma8237_wdc_dack_w ) { } static WRITE_LINE_DEVICE_HANDLER( apollo_dma8237_out_eop ) { + pc_fdc_at_device *fdc = device->machine().device<pc_fdc_at_device>(APOLLO_FDC_TAG); DLOG1(("dma out eop state %02x", state)); - pc_fdc_set_tc_state(device->machine(), state ? 0 : 1); + fdc->tc_w(!state); sc499_set_tc_state(&device->machine(), state); } @@ -1275,81 +1279,23 @@ static DEVICE_RESET(apollo_sio2) #undef VERBOSE #define VERBOSE 0 -static device_t *apollo_fdc_device = NULL; - -static LEGACY_FLOPPY_OPTIONS_START( apollo ) - LEGACY_FLOPPY_OPTION( img2d, "afd", "Apollo floppy disk image", basicdsk_identify_default, basicdsk_construct_default, NULL, - HEADS([2]) - TRACKS([77]) - SECTORS([8]) - SECTOR_LENGTH([1024]) - FIRST_SECTOR_ID([1])) - LEGACY_FLOPPY_OPTIONS_END0 - -static const floppy_interface apollo_fdc_floppy_config = { // - DEVCB_NULL, // - DEVCB_NULL, // - DEVCB_NULL, // - DEVCB_NULL, // - DEVCB_NULL, // - FLOPPY_STANDARD_5_25_DSHD, // - LEGACY_FLOPPY_OPTIONS_NAME(apollo), // - NULL, // - NULL // +static const floppy_format_type apollo_floppy_formats[] = { + FLOPPY_APOLLO_FORMAT, + FLOPPY_MFI_FORMAT, + NULL }; -/************************************* - * Floppy Disk Controller - *************************************/ +static SLOT_INTERFACE_START( apollo_floppies ) + SLOT_INTERFACE( "525hd", FLOPPY_525_HD ) +SLOT_INTERFACE_END -static void apollo_fdc_interrupt(running_machine &machine, int state) { - apollo_pic_set_irq_line( machine.firstcpu, APOLLO_IRQ_FDC, state); -} - -static void apollo_fdc_dma_drq(running_machine &machine, int state) { - apollo_dma_fdc_drq(machine.firstcpu, state); -} - -static device_t *apollo_fdc_get_image(running_machine &machine, - int floppy_index) { - return floppy_get_device(machine, 0); -} - -static device_t * apollo_fdc_get_device(running_machine &machine) { - return apollo_fdc_device; -} - -static const struct pc_fdc_interface apollo_fdc_interface = { - apollo_fdc_interrupt, // - apollo_fdc_dma_drq, // - apollo_fdc_get_image, // - apollo_fdc_get_device // -}; -/*------------------------------------------------- - FDC upd765 at 0x5f800 - 0x5f807 - -------------------------------------------------*/ - -static DEVICE_START( apollo_fdc ) { - DLOG1(("device_start_apollo_fdc")); - apollo_fdc_device = device; - pc_fdc_init(device->machine(), &apollo_fdc_interface); -} - -static DEVICE_RESET( apollo_fdc ) { - DLOG1(("device_reset_apollo_fdc")); - pc_fdc_reset(device->machine()); +void apollo_state::fdc_interrupt(bool state) { + apollo_pic_set_irq_line( machine().firstcpu, APOLLO_IRQ_FDC, state ? ASSERT_LINE : CLEAR_LINE); } -WRITE8_MEMBER(apollo_state::apollo_fdc_w){ - SLOG1(("writing FDC upd765 at offset %X = %02x", offset, data)); - pc_fdc_w(space, offset, data); -} - -READ8_MEMBER(apollo_state::apollo_fdc_r){ - UINT8 data = pc_fdc_r(space, offset); - SLOG1(("reading FDC upd765 at offset %X = %02x", offset, data)); - return data; +void apollo_state::fdc_dma_drq(bool state) { + apollo_dma_fdc_drq(machine().firstcpu, state); } /*************************************************************************** @@ -1452,8 +1398,8 @@ MACHINE_CONFIG_FRAGMENT( apollo ) MCFG_DUART68681_ADD( APOLLO_SIO_TAG, XTAL_3_6864MHz, apollo_sio_config ) MCFG_DUART68681_ADD( APOLLO_SIO2_TAG, XTAL_3_6864MHz, apollo_sio2_config ) - MCFG_UPD765A_ADD(APOLLO_FDC_TAG, pc_fdc_upd765_connected_1_drive_interface) - MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, apollo_fdc_floppy_config) + MCFG_PC_FDC_XT_ADD(APOLLO_FDC_TAG) + MCFG_FLOPPY_DRIVE_ADD(APOLLO_FDC_TAG ":0", apollo_floppies, "525hd", 0, apollo_floppy_formats) MCFG_OMTI8621_ADD(APOLLO_WDC_TAG, apollo_wdc_config) MCFG_SC499_ADD(APOLLO_CTAPE_TAG, apollo_ctape_config) @@ -1469,7 +1415,10 @@ MACHINE_START_MEMBER(apollo_state,apollo) { //MLOG1(("machine_start_apollo")); - device_start_apollo_fdc (machine().device(APOLLO_FDC_TAG)); + pc_fdc_at_device *fdc = machine().device<pc_fdc_at_device>(APOLLO_FDC_TAG); + fdc->setup_intrq_cb(pc_fdc_at_device::line_cb(FUNC(apollo_state::fdc_interrupt), this)); + fdc->setup_drq_cb(pc_fdc_at_device::line_cb(FUNC(apollo_state::fdc_dma_drq), this)); + device_start_apollo_ptm (machine().device(APOLLO_PTM_TAG) ); device_start_apollo_sio(machine().device(APOLLO_SIO_TAG)); device_start_apollo_sio2(machine().device(APOLLO_SIO2_TAG)); @@ -1498,5 +1447,4 @@ MACHINE_RESET_MEMBER(apollo_state,apollo) device_reset_apollo_rtc(machine().device(APOLLO_RTC_TAG)); device_reset_apollo_sio(machine().device(APOLLO_SIO_TAG)); device_reset_apollo_sio2(machine().device(APOLLO_SIO2_TAG)); - device_reset_apollo_fdc(apollo_fdc_device); } diff --git a/src/mess/machine/bebox.c b/src/mess/machine/bebox.c index 08d87797186..1590cc19973 100644 --- a/src/mess/machine/bebox.c +++ b/src/mess/machine/bebox.c @@ -96,7 +96,7 @@ #include "video/cirrus.h" #include "cpu/powerpc/ppc.h" #include "machine/ins8250.h" -#include "machine/pc_fdc.h" +#include "machine/upd765.h" #include "machine/mc146818.h" #include "machine/pic8259.h" #include "machine/pit8253.h" @@ -451,47 +451,22 @@ const ins8250_interface bebox_uart_inteface_3 = * *************************************/ -static void bebox_fdc_interrupt(running_machine &machine, int state) +void bebox_state::fdc_interrupt(bool state) { - bebox_state *drvstate = machine.driver_data<bebox_state>(); - bebox_set_irq_bit(machine, 13, state); - if ( drvstate->m_devices.pic8259_master ) { - pic8259_ir6_w(drvstate->m_devices.pic8259_master, state); + bebox_set_irq_bit(machine(), 13, state); + if ( m_devices.pic8259_master ) { + pic8259_ir6_w(m_devices.pic8259_master, state); } } -static void bebox_fdc_dma_drq(running_machine &machine, int state) +void bebox_state::fdc_dma_drq(bool state) { - bebox_state *drvstate = machine.driver_data<bebox_state>(); - if ( drvstate->m_devices.dma8237_1 ) { - i8237_dreq2_w(drvstate->m_devices.dma8237_1, state); + if ( m_devices.dma8237_1 ) { + i8237_dreq2_w(m_devices.dma8237_1, state); } } - -static device_t *bebox_fdc_get_image(running_machine &machine, int floppy_index) -{ - /* the BeBox boot ROM seems to query for floppy #1 when it should be - * querying for floppy #0 */ - return floppy_get_device(machine, 0); -} - -static device_t * bebox_get_device(running_machine &machine ) -{ - return machine.device("smc37c78"); -} - - -static const struct pc_fdc_interface bebox_fdc_interface = -{ - bebox_fdc_interrupt, - bebox_fdc_dma_drq, - bebox_fdc_get_image, - bebox_get_device -}; - - /************************************* * * 8259 PIC @@ -563,18 +538,11 @@ WRITE8_MEMBER(bebox_state::bebox_800001F0_w ) { ide_controller_w(ide_device(spac READ64_MEMBER(bebox_state::bebox_800003F0_r ) { - UINT64 result = read64be_with_read8_handler(pc_fdc_r, space, offset, mem_mask | 0xFFFF); + UINT64 result = 0; if (((mem_mask >> 8) & 0xFF) == 0) { - result &= ~(0xFF << 8); - result |= ide_controller_r(ide_device(space.machine()), 0x3F6, 1) << 8; - } - - if (((mem_mask >> 0) & 0xFF) == 0) - { - result &= ~(0xFF << 0); - result |= ide_controller_r(ide_device(space.machine()), 0x3F7, 1) << 0; + result |= ide_controller_r(space.machine().device("ide"), 0x3F6, 1) << 8; } return result; } @@ -582,13 +550,8 @@ READ64_MEMBER(bebox_state::bebox_800003F0_r ) WRITE64_MEMBER(bebox_state::bebox_800003F0_w ) { - write64be_with_write8_handler(pc_fdc_w, space, offset, data, mem_mask | 0xFFFF); - if (((mem_mask >> 8) & 0xFF) == 0) - ide_controller_w(ide_device(space.machine()), 0x3F6, 1, (data >> 8) & 0xFF); - - if (((mem_mask >> 0) & 0xFF) == 0) - ide_controller_w(ide_device(space.machine()), 0x3F7, 1, (data >> 0) & 0xFF); + ide_controller_w(space.machine().device("ide"), 0x3F6, 1, (data >> 8) & 0xFF); } @@ -768,17 +731,17 @@ WRITE8_MEMBER(bebox_state::bebox_dma_write_byte ) READ8_MEMBER(bebox_state::bebox_dma8237_fdc_dack_r){ - return pc_fdc_dack_r(machine(),space); + return machine().device<smc37c78_device>("smc37c78")->dma_r(); } WRITE8_MEMBER(bebox_state::bebox_dma8237_fdc_dack_w){ - pc_fdc_dack_w( machine(), space, data ); + machine().device<smc37c78_device>("smc37c78")->dma_w(data); } WRITE_LINE_MEMBER(bebox_state::bebox_dma8237_out_eop){ - pc_fdc_set_tc_state( machine(), state ); + machine().device<smc37c78_device>("smc37c78")->tc_w(state); } static void set_dma_channel(running_machine &machine, int channel, int state) @@ -1067,7 +1030,9 @@ void bebox_state::machine_reset() void bebox_state::machine_start() { - pc_fdc_init(machine(), &bebox_fdc_interface); + smc37c78_device *fdc = machine().device<smc37c78_device>("smc37c78"); + fdc->setup_intrq_cb(smc37c78_device::line_cb(FUNC(bebox_state::fdc_interrupt), this)); + fdc->setup_drq_cb(smc37c78_device::line_cb(FUNC(bebox_state::fdc_dma_drq), this)); } DRIVER_INIT_MEMBER(bebox_state,bebox) diff --git a/src/mess/machine/compis.c b/src/mess/machine/compis.c index 6be6779b958..eee3503983d 100644 --- a/src/mess/machine/compis.c +++ b/src/mess/machine/compis.c @@ -159,12 +159,7 @@ static void compis_keyb_init(compis_state *state) /*-------------------------------------------------------------------------*/ static void compis_fdc_reset(running_machine &machine) { - device_t *fdc = machine.device("upd765"); - - upd765_reset(fdc, 0); - - /* set FDC at reset */ - upd765_reset_w(fdc, 1); + machine.device("upd765")->reset(); } void compis_state::compis_fdc_tc(int state) @@ -172,11 +167,11 @@ void compis_state::compis_fdc_tc(int state) /* Terminal count if iSBX-218A has DMA enabled */ if (ioport("DSW1")->read()) { - upd765_tc_w(m_fdc, state); + m_fdc->tc_w(state); } } -WRITE_LINE_MEMBER( compis_state::compis_fdc_int ) +void compis_state::fdc_irq(bool state) { /* No interrupt requests if iSBX-218A has DMA enabled */ if (!ioport("DSW1")->read() && state) @@ -189,71 +184,15 @@ WRITE_LINE_MEMBER( compis_state::compis_fdc_int ) } } -WRITE_LINE_MEMBER( compis_state::compis_fdc_dma_drq ) +void compis_state::fdc_drq(bool state) { - /* DMA requst if iSBX-218A has DMA enabled */ + /* DMA request if iSBX-218A has DMA enabled */ if (ioport("DSW1")->read() && state) { //compis_dma_drq(state, read); } } -const upd765_interface compis_fdc_interface = -{ - DEVCB_DRIVER_LINE_MEMBER(compis_state, compis_fdc_int), - DEVCB_DRIVER_LINE_MEMBER(compis_state, compis_fdc_dma_drq), - NULL, - UPD765_RDY_PIN_CONNECTED, - {FLOPPY_0, FLOPPY_1, NULL, NULL} -}; - -READ16_MEMBER( compis_state::compis_fdc_dack_r ) -{ - UINT16 data; - data = 0xffff; - /* DMA acknowledge if iSBX-218A has DMA enabled */ - if (ioport("DSW1")->read()) - { - data = upd765_dack_r(m_fdc, space, 0); - } - - return data; -} - -WRITE8_MEMBER( compis_state::compis_fdc_w ) -{ - switch(offset) - { - case 2: - upd765_data_w(m_fdc, space, 0, data); - break; - default: - printf("FDC Unknown Port Write %04X = %04X\n", offset, data); - break; - } -} - -READ8_MEMBER( compis_state::compis_fdc_r ) -{ - UINT16 data; - data = 0xffff; - switch(offset) - { - case 0: - data = upd765_status_r(m_fdc, space, 0); - break; - case 2: - data = upd765_data_r(m_fdc, space, 0); - break; - default: - printf("FDC Unknown Port Read %04X\n", offset); - break; - } - - return data; -} - - /*-------------------------------------------------------------------------*/ /* Bit 0: J5-4 */ diff --git a/src/mess/machine/fd2000.c b/src/mess/machine/fd2000.c index 80831949be4..a0f34dcdc3f 100644 --- a/src/mess/machine/fd2000.c +++ b/src/mess/machine/fd2000.c @@ -86,46 +86,14 @@ static const via6522_interface via_intf = }; -//------------------------------------------------- -// LEGACY_FLOPPY_OPTIONS( fd2000 ) -//------------------------------------------------- - -static LEGACY_FLOPPY_OPTIONS_START( fd2000 ) - LEGACY_FLOPPY_OPTION( fd2000, "d81", "Commodore 1581 Disk Image", d81_dsk_identify, d81_dsk_construct, NULL, NULL ) - //LEGACY_FLOPPY_OPTION( fd2000, "d2m", "CMD FD-2000 Disk Image", d2m_dsk_identify, d2m_dsk_construct, NULL, NULL ) -LEGACY_FLOPPY_OPTIONS_END - - -//------------------------------------------------- -// floppy_interface fd2000_floppy_interface -//------------------------------------------------- - -static const floppy_interface fd2000_floppy_interface = -{ - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - FLOPPY_STANDARD_3_5_DSDD, - LEGACY_FLOPPY_OPTIONS_NAME(fd2000), - "floppy_3_5", +static const floppy_format_type fd2000_floppy_formats[] = { + FLOPPY_MFI_FORMAT, NULL }; - -//------------------------------------------------- -// upd765_interface fdc_intf -//------------------------------------------------- - -static const struct upd765_interface fdc_intf = -{ - DEVCB_NULL, - DEVCB_NULL, - NULL, - UPD765_RDY_PIN_CONNECTED, - { FLOPPY_0, NULL, NULL, NULL } -}; +static SLOT_INTERFACE_START( fd2000_floppies ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) +SLOT_INTERFACE_END //------------------------------------------------- @@ -137,9 +105,9 @@ static MACHINE_CONFIG_FRAGMENT( fd2000 ) MCFG_CPU_PROGRAM_MAP(fd2000_mem) MCFG_VIA6522_ADD(M6522_TAG, 2000000, via_intf) - MCFG_UPD765A_ADD(DP8473_TAG, fdc_intf) + MCFG_UPD765A_ADD(DP8473_TAG, true, true) - MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, fd2000_floppy_interface) + MCFG_FLOPPY_DRIVE_ADD(DP8473_TAG ":0", fd2000_floppies, "525dd", 0, fd2000_floppy_formats) MACHINE_CONFIG_END diff --git a/src/mess/machine/fd2000.h b/src/mess/machine/fd2000.h index 736c972c87b..89738126739 100644 --- a/src/mess/machine/fd2000.h +++ b/src/mess/machine/fd2000.h @@ -17,7 +17,7 @@ #include "emu.h" #include "cpu/m6502/m6502.h" #include "imagedev/flopdrv.h" -#include "formats/d81_dsk.h" +#include "formats/mfi_dsk.h" #include "machine/6522via.h" #include "machine/cbmiec.h" #include "machine/upd765.h" diff --git a/src/mess/machine/genpc.c b/src/mess/machine/genpc.c index 3c1408a3b90..88e185e1745 100644 --- a/src/mess/machine/genpc.c +++ b/src/mess/machine/genpc.c @@ -527,9 +527,9 @@ static INPUT_PORTS_START( ibm5160_mb ) PORT_DIPNAME( 0x02, 0x00, "8087 installed") PORT_DIPSETTING( 0x00, DEF_STR(No) ) PORT_DIPSETTING( 0x02, DEF_STR(Yes) ) - PORT_DIPNAME( 0x01, 0x01, "Any floppy drive installed") - PORT_DIPSETTING( 0x00, DEF_STR(No) ) + PORT_DIPNAME( 0x01, 0x01, "Boot from floppy") PORT_DIPSETTING( 0x01, DEF_STR(Yes) ) + PORT_DIPSETTING( 0x00, DEF_STR(No) ) INPUT_PORTS_END //------------------------------------------------- // input_ports - device-specific input ports diff --git a/src/mess/machine/hec2hrp.c b/src/mess/machine/hec2hrp.c index e00554b2d50..0d06168ab9d 100644 --- a/src/mess/machine/hec2hrp.c +++ b/src/mess/machine/hec2hrp.c @@ -45,7 +45,6 @@ #include "sound/wave.h" /* for K7 sound*/ #include "sound/discrete.h" /* for 1 Bit sound*/ #include "machine/upd765.h" /* for floppy disc controller */ -#include "formats/basicdsk.h" #include "formats/hect_tap.h" #include "includes/hec2hrp.h" @@ -876,11 +875,9 @@ void hector_reset(running_machine &machine, int hr, int with_D2 ) if (with_D2==1) { + upd765a_device *fdc = machine.device<upd765a_device>("upd765"); machine.device("disc2cpu")->execute().set_input_line(INPUT_LINE_RESET, PULSE_LINE); - device_t *fdc = machine.device("upd765"); - machine.device("disc2cpu")->execute().set_input_line(INPUT_LINE_RESET, PULSE_LINE); - upd765_reset(fdc, 1); - upd765_reset_w(fdc, 1); + fdc->reset(); } } diff --git a/src/mess/machine/hecdisk2.c b/src/mess/machine/hecdisk2.c index aaf28a31bb1..de9f75bb5db 100644 --- a/src/mess/machine/hecdisk2.c +++ b/src/mess/machine/hecdisk2.c @@ -27,14 +27,7 @@ #include "includes/hec2hrp.h" -/* Disquette timer*/ -static TIMER_CALLBACK( Callback_DMA_irq ); -static TIMER_CALLBACK( Callback_INT_irq ); - /* Callback uPD request */ -//UPD765_DMA_REQUEST( hector_disc2_fdc_dma_irq ); -static WRITE_LINE_DEVICE_HANDLER( disc2_fdc_interrupt ); -static WRITE_LINE_DEVICE_HANDLER( hector_disc2_fdc_dma_irq ); /* How uPD765 works: * First we send at uPD the string of command (p.e. 9 bytes for read starting by 0x46) on port 60h @@ -48,95 +41,29 @@ static WRITE_LINE_DEVICE_HANDLER( hector_disc2_fdc_dma_irq ); * At this point the Z80 can read the RESULT in port 61h */ -// Define the hardware of the disk - const floppy_interface hector_disc2_floppy_interface = -{ - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - FLOPPY_STANDARD_5_25_DSHD, - LEGACY_FLOPPY_OPTIONS_NAME(hector_disc2), - NULL, - NULL -}; - -/*****************************************************************************/ -/****** Management of the uPD765 for interface with floppy images************/ -/*****************************************************************************/ -/* Hector Disc II uPD765 interface use interrupts and DMA! */ -const upd765_interface hector_disc2_upd765_interface = -{ - DEVCB_LINE(disc2_fdc_interrupt), - DEVCB_LINE(hector_disc2_fdc_dma_irq), - NULL, - UPD765_RDY_PIN_NOT_CONNECTED, - {FLOPPY_0,FLOPPY_1, NULL, NULL} -}; - /*****************************************************************************/ /**** Management of the interrupts (NMI and INT)between uPD765 and Z80 ******/ /*****************************************************************************/ -static void valid_interrupt( running_machine &machine) -{ - hec2hrp_state *state = machine.driver_data<hec2hrp_state>(); - /* Called at each rising state of NMI or RNMI ! */ - - /* Take NMI only if RNMI ok*/ - if ((state->m_hector_disc2_RNMI==1) && (state->m_NMI_current_state==1)) - { - machine.device("disc2cpu")->execute().set_input_line(INPUT_LINE_NMI, CLEAR_LINE); // Clear NMI... - state->m_DMA_timer->adjust(attotime::from_usec(6) );//a little time to let the Z80 terminate he's previous job ! - state->m_NMI_current_state=0; - } -} - void hector_disc2_init( running_machine &machine) { hec2hrp_state *state = machine.driver_data<hec2hrp_state>(); - state->m_DMA_timer = machine.scheduler().timer_alloc(FUNC(Callback_DMA_irq)); - state->m_INT_timer = machine.scheduler().timer_alloc(FUNC(Callback_INT_irq)); -} - -static TIMER_CALLBACK( Callback_DMA_irq ) -{ - hec2hrp_state *state = machine.driver_data<hec2hrp_state>(); - /* To generate the NMI signal (late) when uPD DMA request*/ - machine.device("disc2cpu")->execute().set_input_line(INPUT_LINE_NMI, ASSERT_LINE); //NMI... - state->m_hector_nb_cde =0; // clear the cde length -} - -static TIMER_CALLBACK( Callback_INT_irq ) -{ - /* To generate the INT signal (late) when uPD DMA request*/ - /*device->*/machine.device("disc2cpu")->execute().set_input_line(INPUT_LINE_IRQ0, ASSERT_LINE); + upd765a_device *fdc = machine.device<upd765a_device>("upd765"); + fdc->setup_intrq_cb(upd765a_device::line_cb(FUNC(hec2hrp_state::disc2_fdc_interrupt), state)); + fdc->setup_drq_cb(upd765a_device::line_cb(FUNC(hec2hrp_state::disc2_fdc_dma_irq), state)); } -/* upd765 INT is connected to interrupt of Z80 within a RNMI hardware authorization*/ -static WRITE_LINE_DEVICE_HANDLER( disc2_fdc_interrupt ) +/* upd765 INT is connected to interrupt of Z80 within a RNMI hardware authorization */ +void hec2hrp_state::disc2_fdc_interrupt(bool state) { - hec2hrp_state *drvstate = device->machine().driver_data<hec2hrp_state>(); - device->machine().device("disc2cpu")->execute().set_input_line(INPUT_LINE_IRQ0, CLEAR_LINE); - if (state) - drvstate->m_INT_timer->adjust(attotime::from_usec(500) );//a little time to let the Z80 terminate he's previous job ! + m_IRQ_current_state = state; + machine().device("disc2cpu")->execute().set_input_line(INPUT_LINE_IRQ0, state && m_hector_disc2_RNMI ? ASSERT_LINE : CLEAR_LINE); } -static WRITE_LINE_DEVICE_HANDLER( hector_disc2_fdc_dma_irq ) +/* upd765 DRQ is connected to NMI of Z80 within a RNMI hardware authorization */ +void hec2hrp_state::disc2_fdc_dma_irq(bool state) { - hec2hrp_state *drvstate = device->machine().driver_data<hec2hrp_state>(); - /* upd765 DRQ is connected to NMI of Z80 within a RNMI hardware authorization*/ - /* Here the most difficult on this machine : - The DMA request come with the uPD765 "soft" immediately, - against the true hard uPD765. In the real life, the uPD had - to seach for the sector before ! - So, we had to memorize the signal (the DMA is a pulse) - until disc2's Z80 is ready to take the NMI interupt (when - he had set the RNMI authorization) ! */ - - if (state==1) - drvstate->m_NMI_current_state = state; - valid_interrupt(device->machine()); + m_NMI_current_state = state; + machine().device("disc2cpu")->execute().set_input_line(INPUT_LINE_NMI, state && m_hector_disc2_RNMI ? ASSERT_LINE : CLEAR_LINE); } // RESET the disc2 Unit ! @@ -144,10 +71,8 @@ void hector_disc2_reset(running_machine &machine) { hec2hrp_state *state = machine.driver_data<hec2hrp_state>(); // Initialization Disc2 unit - machine.device("disc2cpu" )->execute().set_input_line(INPUT_LINE_RESET, PULSE_LINE); - //switch ON and OFF the reset line uPD - upd765_reset_w(machine.device("upd765"), 1); - upd765_reset_w(machine.device("upd765"), 0); + machine.device("disc2cpu")->execute().set_input_line(INPUT_LINE_RESET, PULSE_LINE); + machine.device<upd765a_device>("upd765")->reset(); // Select ROM memory to cold restart state->membank("bank3")->set_entry(DISCII_BANK_ROM); @@ -157,6 +82,7 @@ void hector_disc2_reset(running_machine &machine) state->m_hector_disc2_data_read=0; /* Data send by Hector to Disc 2 when PC2=true */ state->m_hector_disc2_data_write=0; /* Data send by Disc 2 to Hector when Write Port I/O 40 */ state->m_hector_disc2_RNMI = 0; /* State of I/O 50 D5 = authorization for INT / NMI */ + state->m_IRQ_current_state=0; /* Clear the IRQ active request */ state->m_NMI_current_state=0; /* Clear the DMA active request */ } @@ -219,109 +145,18 @@ READ8_HANDLER( hector_disc2_io50_port_r) /*Read memory info write ready*/ WRITE8_HANDLER( hector_disc2_io50_port_w) /* I/O Port to the stuff of Disc2*/ { hec2hrp_state *state = space.machine().driver_data<hec2hrp_state>(); - device_t *fdc = space.machine().device("upd765"); + upd765a_device *fdc = space.machine().device<upd765a_device>("upd765"); /* FDC Motor Control - Bit 0/1 defines the state of the FDD 0/1 motor */ - floppy_mon_w(floppy_get_device(space.machine(), 0), BIT(data, 0)); // Moteur floppy A: - floppy_mon_w(floppy_get_device(space.machine(), 1), BIT(data, 1)); // Moteur floppy B: - floppy_drive_set_ready_state(floppy_get_device(space.machine(), 0), FLOPPY_DRIVE_READY,!BIT(data, 0)); - floppy_drive_set_ready_state(floppy_get_device(space.machine(), 1), FLOPPY_DRIVE_READY,!BIT(data, 1)); + space.machine().device<floppy_connector>("upd765:0")->get_device()->mon_w(BIT(data, 0)); // Moteur floppy A: + space.machine().device<floppy_connector>("upd765:1")->get_device()->mon_w(BIT(data, 1)); // Moteur floppy B: /* Write bit TC uPD765 on D4 of port I/O 50 */ - upd765_tc_w(fdc, BIT(data, 4)); // Seems not used... + fdc->tc_w(BIT(data, 4)); /* Authorization interrupt and NMI with RNMI signal*/ state->m_hector_disc2_RNMI = BIT(data, 5); - - /* if RNMI is OK, try to lauch an NMI*/ - if (state->m_hector_disc2_RNMI) - valid_interrupt(space.machine()); -} - -//Here we must take the exchange with uPD against AM_DEVREADWRITE -// Because we had to add D6 = 1 when write is done with 0x28 in ST0 back - -// AM_RANGE(0x061,0x061) AM_DEVREADWRITE("upd765",upd765_data_r,upd765_data_w) -READ8_HANDLER( hector_disc2_io61_port_r) -{ - hec2hrp_state *state = space.machine().driver_data<hec2hrp_state>(); - UINT8 data; - device_t *fdc = space.machine().device("upd765"); - data = upd765_data_r(fdc,space, 0); //Get the result - -// if ST0 == 0x28 (drive A:) or 0x29 (drive B:) => add 0x40 -// and correct the ST1 and ST2 (patch) - if ((state->m_hector_flag_result == 3) & ((data==0x28) | (data==0x29)) ) // are we in the problem? - { - data=data + 0x40; - state->m_hector_flag_result--; - } - // Nothing to do in over case! - if (state->m_hector_flag_result == 3) - state->m_hector_flag_result = 0; - - if ((state->m_hector_flag_result == 2) & (data==0x00) ) - { - data=/*data +*/ 0x04; - state->m_hector_flag_result--; - } - if ((state->m_hector_flag_result == 1) & (data==0x00) ) - { - data=/*data + */0x10; - state->m_hector_flag_result=0; // End ! - } - #ifdef hector_trace - if (state->m_print==1) - printf(" _%x",data); - #endif - state->m_hector_nb_cde =0; // clear the cde length - return data; -} -WRITE8_HANDLER( hector_disc2_io61_port_w) -{ - hec2hrp_state *state = space.machine().driver_data<hec2hrp_state>(); - /* Data useful to patch the RESULT in case of write command */ - state->m_hector_cmd[9]=state->m_hector_cmd[8]; //hector_cmd_8 = Cde number when state->m_hector_nb_cde = 9 - state->m_hector_cmd[8]=state->m_hector_cmd[7]; //hector_cmd_7 = Drive - state->m_hector_cmd[7]=state->m_hector_cmd[6]; //hector_cmd_6 = C - state->m_hector_cmd[6]=state->m_hector_cmd[5]; //hector_cmd_5 = H - state->m_hector_cmd[5]=state->m_hector_cmd[4]; //hector_cmd_4 = R - state->m_hector_cmd[4]=state->m_hector_cmd[3]; //hector_cmd_3 = N - state->m_hector_cmd[3]=state->m_hector_cmd[2]; //hector_cmd_2 = EOT - state->m_hector_cmd[2]=state->m_hector_cmd[1]; //hector_cmd_1 = GPL - state->m_hector_cmd[1]=state->m_hector_cmd[0]; //hector_cmd_0 = DTL - state->m_hector_cmd[0] = data; - // Increase the length cde! - state->m_hector_nb_cde++; - - // check if current commande is write cmde. - if (((state->m_hector_cmd[8] & 0x1f)== 0x05) & (state->m_hector_nb_cde==9) ) /*Detect wrtie commande*/ - state->m_hector_flag_result = 3; // here we are! -#ifdef hector_trace - if (state->m_hector_nb_cde==6 ) /*Detect 1 octet command*/ - { - printf("\n commande = %x, %x, %x, %x, %x, %x Result = ", state->m_hector_cmd[5], state->m_hector_cmd[4], state->m_hector_cmd[3], state->m_hector_cmd[2], state->m_hector_cmd[1], data ); - state->m_print=1; - } - else - state->m_print=0; -#endif - - device_t *fdc = space.machine().device("upd765"); - upd765_data_w(fdc,space, 0, data); -} - -// AM_RANGE(0x070,0x07f) AM_DEVREADWRITE("upd765",upd765_dack_r,upd765_dack_w) -READ8_HANDLER( hector_disc2_io70_port_r) // Gestion du DMA -{ - UINT8 data; - device_t *fdc = space.machine().device("upd765"); - data = upd765_dack_r(fdc,space, 0); - return data; -} -WRITE8_HANDLER( hector_disc2_io70_port_w) -{ - device_t *fdc = space.machine().device("upd765"); - upd765_dack_w(fdc,space, 0, data); + space.machine().device("disc2cpu")->execute().set_input_line(INPUT_LINE_IRQ0, state->m_IRQ_current_state && state->m_hector_disc2_RNMI ? ASSERT_LINE : CLEAR_LINE); + space.machine().device("disc2cpu")->execute().set_input_line(INPUT_LINE_NMI, state->m_NMI_current_state && state->m_hector_disc2_RNMI ? ASSERT_LINE : CLEAR_LINE); } diff --git a/src/mess/machine/iq151_disc2.c b/src/mess/machine/iq151_disc2.c index 5ff4df25017..634e8893f13 100644 --- a/src/mess/machine/iq151_disc2.c +++ b/src/mess/machine/iq151_disc2.c @@ -6,46 +6,28 @@ #include "emu.h" #include "iq151_disc2.h" +#include "formats/mfi_dsk.h" +#include "formats/iq151_dsk.h" /*************************************************************************** IMPLEMENTATION ***************************************************************************/ -static LEGACY_FLOPPY_OPTIONS_START( iq151_disc2 ) - LEGACY_FLOPPY_OPTION( iq151_disk, "iqd", "IQ-151 disk image", basicdsk_identify_default, basicdsk_construct_default, NULL, - HEADS([1]) - TRACKS([77]) - SECTORS([26]) - SECTOR_LENGTH([128]) - FIRST_SECTOR_ID([1])) -LEGACY_FLOPPY_OPTIONS_END - -static const floppy_interface iq151_disc2_intf = -{ - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - FLOPPY_STANDARD_8_SSSD, - LEGACY_FLOPPY_OPTIONS_NAME(iq151_disc2), - "floppy_8", +static const floppy_format_type iq151_disc2_floppy_formats[] = { + FLOPPY_IQ151_FORMAT, + FLOPPY_MFI_FORMAT, NULL }; -static const upd765_interface iq151_disc2_fdc_intf = -{ - DEVCB_NULL, - DEVCB_NULL, - NULL, - UPD765_RDY_PIN_NOT_CONNECTED, - { NULL, FLOPPY_0, FLOPPY_1, NULL } -}; +static SLOT_INTERFACE_START( iq151_disc2_floppies ) + SLOT_INTERFACE( "8sssd", FLOPPY_8_SSSD ) +SLOT_INTERFACE_END static MACHINE_CONFIG_FRAGMENT( iq151_disc2 ) - MCFG_UPD72065_ADD("fdc", iq151_disc2_fdc_intf) - MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(iq151_disc2_intf) + MCFG_UPD72065_ADD("fdc", false, true) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", iq151_disc2_floppies, "8sssd", 0, iq151_disc2_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:2", iq151_disc2_floppies, "8sssd", 0, iq151_disc2_floppy_formats) MACHINE_CONFIG_END ROM_START( iq151_disc2 ) @@ -129,10 +111,12 @@ void iq151_disc2_device::read(offs_t offset, UINT8 &data) void iq151_disc2_device::io_read(offs_t offset, UINT8 &data) { + /* This is gross */ + address_space *space = NULL; if (offset == 0xaa) - data = upd765_status_r(m_fdc, machine().driver_data()->generic_space(), 0); + data = m_fdc->msr_r(*space, 0, 0xff); else if (offset == 0xab) - data = upd765_data_r(m_fdc, machine().driver_data()->generic_space(), 0); + data = m_fdc->fifo_r(*space, 0, 0xff); } //------------------------------------------------- @@ -141,8 +125,9 @@ void iq151_disc2_device::io_read(offs_t offset, UINT8 &data) void iq151_disc2_device::io_write(offs_t offset, UINT8 data) { + address_space *space = NULL; if (offset == 0xab) - upd765_data_w(m_fdc, machine().driver_data()->generic_space(), 0, data); + m_fdc->fifo_w(*space, 0, data, 0xff); else if (offset == 0xac) m_rom_enabled = (data == 0x01); } diff --git a/src/mess/machine/iq151_disc2.h b/src/mess/machine/iq151_disc2.h index 524a469775e..de62e6d4d30 100644 --- a/src/mess/machine/iq151_disc2.h +++ b/src/mess/machine/iq151_disc2.h @@ -6,7 +6,6 @@ #include "emu.h" #include "machine/iq151cart.h" #include "machine/upd765.h" -#include "formats/basicdsk.h" //************************************************************************** // TYPE DEFINITIONS @@ -39,7 +38,7 @@ protected: private: - required_device<device_t> m_fdc; + required_device<upd765a_device> m_fdc; UINT8 * m_rom; bool m_rom_enabled; }; diff --git a/src/mess/machine/isa.h b/src/mess/machine/isa.h index 3e0a8b755b8..5f7ea1b92de 100644 --- a/src/mess/machine/isa.h +++ b/src/mess/machine/isa.h @@ -150,6 +150,9 @@ public: void install_device(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name); void install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler); void install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_space_func rhandler, const char* rhandler_name, write8_space_func whandler, const char *whandler_name); + template<typename T> void install_device(offs_t addrstart, offs_t addrend, T &device, void (T::*map)(address_map &map, device_t &device), int bits = 8, UINT64 unitmask = 0xffffffffffffffff) { + m_maincpu->space(AS_IO).install_device(addrstart, addrend, device, map, bits, unitmask); + } void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data); void install_rom(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, const char *region); void install_memory(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name); diff --git a/src/mess/machine/isa_fdc.c b/src/mess/machine/isa_fdc.c index 98664fb9d62..bf877535adb 100644 --- a/src/mess/machine/isa_fdc.c +++ b/src/mess/machine/isa_fdc.c @@ -6,480 +6,159 @@ #include "emu.h" #include "machine/isa_fdc.h" -#include "machine/upd765.h" +#include "machine/pc_fdc.h" #include "imagedev/flopdrv.h" #include "formats/pc_dsk.h" #include "machine/idectrl.h" +#include "formats/pc_dsk.h" +#include "formats/mfi_dsk.h" -static DECLARE_READ8_DEVICE_HANDLER ( pc_fdc_r ); -static DECLARE_WRITE8_DEVICE_HANDLER ( pc_fdc_w ); - -/* if not 1, DACK and TC inputs to FDC are disabled, and DRQ and IRQ are held - * at high impedance i.e they are not affective */ -#define PC_FDC_FLAGS_DOR_DMA_ENABLED (1<<3) -#define PC_FDC_FLAGS_DOR_FDC_ENABLED (1<<2) -#define PC_FDC_FLAGS_DOR_MOTOR_ON (1<<4) - -#define LOG_FDC 0 -static const floppy_interface ibmpc_floppy_interface = -{ - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - FLOPPY_STANDARD_5_25_DSHD, - LEGACY_FLOPPY_OPTIONS_NAME(pc), - "floppy_5_25", +static const floppy_format_type pc_floppy_formats[] = { + FLOPPY_PC_FORMAT, + FLOPPY_MFI_FORMAT, NULL }; -static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_interrupt ); -static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_dma_drq ); -static UPD765_GET_IMAGE ( pc_fdc_get_image ); +static SLOT_INTERFACE_START( pc_dd_floppies ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) + SLOT_INTERFACE( "35dd", FLOPPY_35_DD ) +SLOT_INTERFACE_END -const upd765_interface pc_fdc_upd765_not_connected_interface = -{ - DEVCB_LINE(pc_fdc_hw_interrupt), - DEVCB_LINE(pc_fdc_hw_dma_drq), - pc_fdc_get_image, - UPD765_RDY_PIN_NOT_CONNECTED, - {FLOPPY_0, FLOPPY_1, NULL, NULL} -}; +static SLOT_INTERFACE_START( pc_hd_floppies ) + SLOT_INTERFACE( "525hd", FLOPPY_525_HD ) + SLOT_INTERFACE( "35hd", FLOPPY_35_HD ) +SLOT_INTERFACE_END -static MACHINE_CONFIG_FRAGMENT( fdc_config ) - MCFG_UPD765A_ADD("upd765", pc_fdc_upd765_not_connected_interface) - - MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(ibmpc_floppy_interface) +static MACHINE_CONFIG_FRAGMENT( cfg_xt ) + MCFG_PC_FDC_XT_ADD("fdc") + MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_dd_floppies, "525dd", 0, pc_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_dd_floppies, "525dd", 0, pc_floppy_formats) MACHINE_CONFIG_END -//************************************************************************** -// GLOBAL VARIABLES -//************************************************************************** - -const device_type ISA8_FDC = &device_creator<isa8_fdc_device>; +static MACHINE_CONFIG_FRAGMENT( cfg_at ) + MCFG_PC_FDC_AT_ADD("fdc") + MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", 0, pc_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", 0, pc_floppy_formats) +MACHINE_CONFIG_END -//------------------------------------------------- -// machine_config_additions - device-specific -// machine configurations -//------------------------------------------------- +static MACHINE_CONFIG_FRAGMENT( cfg_smc ) + MCFG_SMC37C78_ADD("fdc") + MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", 0, pc_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", 0, pc_floppy_formats) +MACHINE_CONFIG_END -machine_config_constructor isa8_fdc_device::device_mconfig_additions() const -{ - return MACHINE_CONFIG_NAME( fdc_config ); -} +static MACHINE_CONFIG_FRAGMENT( cfg_ps2 ) + MCFG_N82077AA_ADD("fdc", n82077aa_device::MODE_PS2) + MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", 0, pc_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", 0, pc_floppy_formats) +MACHINE_CONFIG_END -//************************************************************************** -// LIVE DEVICE -//************************************************************************** +static MACHINE_CONFIG_FRAGMENT( cfg_superio ) + MCFG_PC_FDC_SUPERIO_ADD("fdc") + MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", 0, pc_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", 0, pc_floppy_formats) +MACHINE_CONFIG_END -//------------------------------------------------- -// isa8_fdc_device - constructor -//------------------------------------------------- - -isa8_fdc_device::isa8_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : - device_t(mconfig, ISA8_FDC, "Diskette Drive Adapter", tag, owner, clock), - device_isa8_card_interface(mconfig, *this), - m_upd765(*this, "upd765") -{ -} isa8_fdc_device::isa8_fdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : - device_t(mconfig, type, name, tag, owner, clock), - device_isa8_card_interface(mconfig, *this), - m_upd765(*this, "upd765") + device_t(mconfig, type, name, tag, owner, clock), + device_isa8_card_interface(mconfig, *this), + fdc(*this, "fdc") { } -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - void isa8_fdc_device::device_start() { set_isa_device(); - m_isa->install_device(this, 0x03f0, 0x03f7, 0, 0, FUNC(pc_fdc_r), FUNC(pc_fdc_w) ); + m_isa->install_device(0x03f0, 0x03f7, *fdc, &pc_fdc_interface::map); m_isa->set_dma_channel(2, this, TRUE); -} -//------------------------------------------------- -// device_reset - device-specific reset -//------------------------------------------------- + fdc->setup_intrq_cb(pc_fdc_interface::line_cb(FUNC(isa8_fdc_device::irq_w), this)); + fdc->setup_drq_cb(pc_fdc_interface::line_cb(FUNC(isa8_fdc_device::drq_w), this)); +} void isa8_fdc_device::device_reset() { - status_register_a = 0; - status_register_b = 0; - digital_output_register = 0; - tape_drive_register = 0; - data_rate_register = 2; - digital_input_register = 0x07f; - configuration_control_register = 0; - tc_state = 0; - dma_state = 0; - int_state = 0; - - upd765_reset(m_upd765,0); - - /* set FDC at reset */ - upd765_reset_w(m_upd765, 1); } -static device_t *get_floppy_subdevice(device_t *device, int drive) +void isa8_fdc_device::irq_w(bool state) { - switch(drive) { - case 0 : return device->subdevice(FLOPPY_0); - case 1 : return device->subdevice(FLOPPY_1); - case 2 : return device->subdevice(FLOPPY_2); - case 3 : return device->subdevice(FLOPPY_3); - } - return NULL; + m_isa->irq6_w(state ? ASSERT_LINE : CLEAR_LINE); } -static UPD765_GET_IMAGE ( pc_fdc_get_image ) +void isa8_fdc_device::drq_w(bool state) { - isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device->owner()); - - return get_floppy_subdevice(fdc, fdc->digital_output_register & 0x03); + m_isa->drq2_w(state ? ASSERT_LINE : CLEAR_LINE); } -static WRITE_LINE_DEVICE_HANDLER( pc_fdc_set_tc_state) +UINT8 isa8_fdc_device::dack_r(int line) { - isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device); - /* store state */ - fdc->tc_state = state; - - /* if dma is not enabled, tc's are not acknowledged */ - if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)!=0) - { - upd765_tc_w(fdc->m_upd765, state); - } + return fdc->dma_r(); } -static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_interrupt ) +void isa8_fdc_device::dack_w(int line, UINT8 data) { - isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device->owner()); - - fdc->int_state = state; - - /* if dma is not enabled, irq's are masked */ - if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)==0) - return; - - // not masked, send interrupt request - fdc->m_isa->irq6_w(state); + return fdc->dma_w(data); } - -static WRITE_LINE_DEVICE_HANDLER( pc_fdc_hw_dma_drq ) +void isa8_fdc_device::eop_w(int state) { - isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device->owner()); - fdc->dma_state = state; - - /* if dma is not enabled, drqs are masked */ - if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)==0) - return; - - // not masked, send dma request - fdc->m_isa->drq2_w(state); + fdc->tc_w(state == ASSERT_LINE); } - - -static WRITE8_DEVICE_HANDLER( pc_fdc_data_rate_w ) +isa8_fdc_xt_device::isa8_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_XT, "ISA 8bits XT FDC hookup", tag, owner, clock) { - isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device); - if ((data & 0x080)!=0) - { - /* set ready state */ - upd765_ready_w(fdc->m_upd765,1); - - /* toggle reset state */ - upd765_reset_w(fdc->m_upd765, 1); - upd765_reset_w(fdc->m_upd765, 0); - - /* bit is self-clearing */ - data &= ~0x080; - } - - fdc->data_rate_register = data; + m_shortname = "isa8_fdc_xt"; } - - -/* FDC Digitial Output Register (DOR) - - |7|6|5|4|3|2|1|0| - | | | | | | `------ floppy drive select (0=A, 1=B, 2=floppy C, ...) - | | | | | `-------- 1 = FDC enable, 0 = hold FDC at reset - | | | | `---------- 1 = DMA & I/O interface enabled - | | | `------------ 1 = turn floppy drive A motor on - | | `-------------- 1 = turn floppy drive B motor on - | `---------------- 1 = turn floppy drive C motor on - `------------------ 1 = turn floppy drive D motor on - */ - -static WRITE8_DEVICE_HANDLER( pc_fdc_dor_w ) +machine_config_constructor isa8_fdc_xt_device::device_mconfig_additions() const { - isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device); - int selected_drive; - int floppy_count; - - floppy_count = floppy_get_count(space.machine()); - - if (floppy_count > (fdc->digital_output_register & 0x03)) - floppy_drive_set_ready_state(get_floppy_subdevice(device, fdc->digital_output_register & 0x03), 1, 0); - - fdc->digital_output_register = data; - - selected_drive = data & 0x03; - - /* set floppy drive motor state */ - if (floppy_count > 0) - floppy_mon_w(get_floppy_subdevice(device, 0), !BIT(data, 4)); - if (floppy_count > 1) - floppy_mon_w(get_floppy_subdevice(device, 1), !BIT(data, 5)); - if (floppy_count > 2) - floppy_mon_w(get_floppy_subdevice(device, 2), !BIT(data, 6)); - if (floppy_count > 3) - floppy_mon_w(get_floppy_subdevice(device, 3), !BIT(data, 7)); - - if ((data>>4) & (1<<selected_drive)) - { - if (floppy_count > selected_drive) - floppy_drive_set_ready_state(get_floppy_subdevice(device, selected_drive), 1, 0); - } - - /* changing the DMA enable bit, will affect the terminal count state - from reaching the fdc - if dma is enabled this will send it through - otherwise it will be ignored */ - pc_fdc_set_tc_state(device, fdc->tc_state); - - /* changing the DMA enable bit, will affect the dma drq state - from reaching us - if dma is enabled this will send it through - otherwise it will be ignored */ - pc_fdc_hw_dma_drq(fdc->m_upd765, fdc->dma_state); - - /* changing the DMA enable bit, will affect the irq state - from reaching us - if dma is enabled this will send it through - otherwise it will be ignored */ - pc_fdc_hw_interrupt(fdc->m_upd765, fdc->int_state); - - /* reset? */ - if ((fdc->digital_output_register & PC_FDC_FLAGS_DOR_FDC_ENABLED)==0) - { - /* yes */ - - /* pc-xt expects a interrupt to be generated - when the fdc is reset. - In the FDC docs, it states that a INT will - be generated if READY input is true when the - fdc is reset. - - It also states, that outputs to drive are set to 0. - Maybe this causes the drive motor to go on, and therefore - the ready line is set. - - This in return causes a int?? --- - - - what is not yet clear is if this is a result of the drives ready state - changing... - */ - upd765_ready_w(fdc->m_upd765, 1); - - /* set FDC at reset */ - upd765_reset_w(fdc->m_upd765, 1); - } - else - { - pc_fdc_set_tc_state(device, 0); - - /* release reset on fdc */ - upd765_reset_w(fdc->m_upd765, 0); - } + return MACHINE_CONFIG_NAME(cfg_xt); } -#define RATE_250 2 -#define RATE_300 1 -#define RATE_500 0 -#define RATE_1000 3 - -static void pc_fdc_check_data_rate(isa8_fdc_device *fdc, running_machine &machine) +isa8_fdc_at_device::isa8_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_AT, "ISA 8bits AT FDC hookup", tag, owner, clock) { - device_t *device = get_floppy_subdevice(fdc, fdc->digital_output_register & 0x03); - floppy_image_legacy *image; - int tracks, sectors, rate; - - upd765_set_bad(fdc->m_upd765, 0); // unset in case format is unknown - if (!device) return; - image = flopimg_get_image(device); - if (!image) return; - tracks = floppy_get_tracks_per_disk(image); - tracks -= (tracks % 10); // ignore extra tracks - floppy_get_sector_count(image, 0, 0, §ors); - - if (tracks == 40) { - if ((fdc->data_rate_register != RATE_250) && (fdc->data_rate_register != RATE_300)) - upd765_set_bad(fdc->m_upd765, 1); - return; - } else if (tracks == 80) { - if (sectors <= 14) rate = RATE_250; // 720KB 5 1/4 and 3 1/2 - else if (sectors <= 24) rate = RATE_500; // 1.2MB 5 1/4 and 1.44MB 3 1/2 - else rate = RATE_1000; // 2.88MB 3 1/2 - } else return; - - if (rate != (fdc->data_rate_register & 3)) - upd765_set_bad(fdc->m_upd765, 1); + m_shortname = "isa8_fdc_at"; } - -static READ8_DEVICE_HANDLER ( pc_fdc_r ) +machine_config_constructor isa8_fdc_at_device::device_mconfig_additions() const { - UINT8 data = 0xff; - - isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device); - device_t *hdd = NULL; - switch(offset) - { - case 0: /* status register a */ - case 1: /* status register b */ - data = 0x00; - break; - case 2: - data = fdc->digital_output_register; - break; - case 3: /* tape drive select? */ - break; - case 4: - data = upd765_status_r(fdc->m_upd765, space, 0); - break; - case 5: - data = upd765_data_r(fdc->m_upd765, space, offset); - break; - case 6: /* FDC reserved */ - hdd = space.machine().device(":board3:ide:ide"); - if (hdd) - data = ide_controller16_r(hdd, space, 0x3f6/2, 0x00ff); - break; - case 7: - device_t *dev = get_floppy_subdevice(device, fdc->digital_output_register & 0x03); - data = fdc->digital_input_register; - if(dev!=NULL) data |= (!floppy_dskchg_r(dev)<<7); - break; - } - - if (LOG_FDC) - logerror("pc_fdc_r(): pc=0x%08x offset=%d result=0x%02X\n", (unsigned) space.machine().firstcpu->pc(), offset, data); - return data; + return MACHINE_CONFIG_NAME(cfg_at); } - - -static WRITE8_DEVICE_HANDLER ( pc_fdc_w ) +isa8_fdc_smc_device::isa8_fdc_smc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_XT, "ISA 8bits SMC FDC hookup", tag, owner, clock) { - isa8_fdc_device *fdc = downcast<isa8_fdc_device *>(device); - - if (LOG_FDC) - logerror("pc_fdc_w(): pc=0x%08x offset=%d data=0x%02X\n", (unsigned) space.machine().firstcpu->pc(), offset, data); - pc_fdc_check_data_rate(fdc,space.machine()); // check every time a command may start - device_t *hdd = NULL; - - switch(offset) - { - case 0: /* n/a */ - case 1: /* n/a */ - break; - case 2: - pc_fdc_dor_w(device, space, 0, data, mem_mask); - break; - case 3: - /* tape drive select? */ - break; - case 4: - pc_fdc_data_rate_w(device, space, 0, data, mem_mask); - break; - case 5: - upd765_data_w(fdc->m_upd765, space, 0, data); - break; - case 6: - /* FDC reserved */ - hdd = space.machine().device(":board3:ide:ide"); - if (hdd) - ide_controller16_w(hdd, space, 0x3f6/2, data, 0x00ff); - break; - case 7: - /* Configuration Control Register - * - * Currently unimplemented; bits 1-0 are supposed to control data - * flow rates: - * 0 0 500 kbps - * 0 1 300 kbps - * 1 0 250 kbps - * 1 1 1000 kbps - */ - pc_fdc_data_rate_w(device, space, 0, data & 3, mem_mask); - break; - } + m_shortname = "isa8_fdc_smc"; } -UINT8 isa8_fdc_device::dack_r(int line) +machine_config_constructor isa8_fdc_smc_device::device_mconfig_additions() const { - /* what is output if dack is not acknowledged? */ - int data = 0x0ff; - - /* if dma is not enabled, dacks are not acknowledged */ - if ((digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)!=0) - { - data = upd765_dack_r(m_upd765, machine().driver_data()->generic_space(), 0); - } - - return data; + return MACHINE_CONFIG_NAME(cfg_smc); } -void isa8_fdc_device::dack_w(int line,UINT8 data) +isa8_fdc_ps2_device::isa8_fdc_ps2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_PS2, "ISA 8bits PS/2 FDC hookup", tag, owner, clock) { - /* if dma is not enabled, dacks are not issued */ - if ((digital_output_register & PC_FDC_FLAGS_DOR_DMA_ENABLED)!=0) - { - /* dma acknowledge - and send byte to fdc */ - upd765_dack_w(m_upd765, machine().driver_data()->generic_space(), 0,data); - } + m_shortname = "isa8_fdc_ps2"; } -void isa8_fdc_device::eop_w(int state) + +machine_config_constructor isa8_fdc_ps2_device::device_mconfig_additions() const { - pc_fdc_set_tc_state( this, state); + return MACHINE_CONFIG_NAME(cfg_ps2); } -static MACHINE_CONFIG_FRAGMENT( fdc_smc_config ) - MCFG_SMC37C78_ADD("upd765", pc_fdc_upd765_not_connected_interface) - - MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(ibmpc_floppy_interface) -MACHINE_CONFIG_END - -//************************************************************************** -// GLOBAL VARIABLES -//************************************************************************** - -const device_type ISA8_FDC_SMC = &device_creator<isa8_fdc_smc_device>; - -//------------------------------------------------- -// machine_config_additions - device-specific -// machine configurations -//------------------------------------------------- - -machine_config_constructor isa8_fdc_smc_device::device_mconfig_additions() const +isa8_fdc_superio_device::isa8_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_SUPERIO, "ISA 8bits SUPERIO FDC hookup", tag, owner, clock) { - return MACHINE_CONFIG_NAME( fdc_smc_config ); + m_shortname = "isa8_fdc_superio"; } -//------------------------------------------------- -// isa8_fdc_smc_device - constructor -//------------------------------------------------- - -isa8_fdc_smc_device::isa8_fdc_smc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : - isa8_fdc_device(mconfig, ISA8_FDC_SMC, "Diskette Drive Adapter (SMC37C78)", tag, owner, clock) +machine_config_constructor isa8_fdc_superio_device::device_mconfig_additions() const { + return MACHINE_CONFIG_NAME(cfg_superio); } +const device_type ISA8_FDC_XT = &device_creator<isa8_fdc_xt_device>; +const device_type ISA8_FDC_AT = &device_creator<isa8_fdc_at_device>; +const device_type ISA8_FDC_SMC = &device_creator<isa8_fdc_smc_device>; +const device_type ISA8_FDC_PS2 = &device_creator<isa8_fdc_ps2_device>; +const device_type ISA8_FDC_SUPERIO = &device_creator<isa8_fdc_superio_device>; diff --git a/src/mess/machine/isa_fdc.h b/src/mess/machine/isa_fdc.h index bd37f4bb968..3d251391492 100644 --- a/src/mess/machine/isa_fdc.h +++ b/src/mess/machine/isa_fdc.h @@ -10,6 +10,7 @@ #include "emu.h" #include "machine/isa.h" +#include "machine/upd765.h" //************************************************************************** // TYPE DEFINITIONS @@ -18,66 +19,65 @@ // ======================> isa8_fdc_device class isa8_fdc_device : - public device_t, - public device_isa8_card_interface + public device_t, + public device_isa8_card_interface { public: - // construction/destruction - isa8_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - isa8_fdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); + // construction/destruction + isa8_fdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); + + required_device<pc_fdc_interface> fdc; - // optional information overrides - virtual machine_config_constructor device_mconfig_additions() const; protected: - // device-level overrides - virtual void device_start(); - virtual void device_reset(); - virtual void device_config_complete() { m_shortname = "isa_fdc"; } + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + + virtual UINT8 dack_r(int line); + virtual void dack_w(int line, UINT8 data); + virtual void eop_w(int state); + private: - // internal state -public: - virtual UINT8 dack_r(int line); - virtual void dack_w(int line,UINT8 data); - virtual void eop_w(int state); - - int status_register_a; - int status_register_b; - int digital_output_register; - int tape_drive_register; - int data_rate_register; - int digital_input_register; - int configuration_control_register; - - /* stored tc state - state present at pins */ - int tc_state; - /* stored dma drq state */ - int dma_state; - /* stored int state */ - int int_state; - - required_device<device_t> m_upd765; -}; + void irq_w(bool state); + void drq_w(bool state); +}; -// device type definition -extern const device_type ISA8_FDC; +class isa8_fdc_xt_device : public isa8_fdc_device { +public: + isa8_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; +}; -// ======================> isa8_fdc_smc_device +class isa8_fdc_at_device : public isa8_fdc_device { +public: + isa8_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; +}; -class isa8_fdc_smc_device : - public isa8_fdc_device -{ +class isa8_fdc_smc_device : public isa8_fdc_device { public: - // construction/destruction - isa8_fdc_smc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + isa8_fdc_smc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; +}; - // optional information overrides +class isa8_fdc_ps2_device : public isa8_fdc_device { +public: + isa8_fdc_ps2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); virtual machine_config_constructor device_mconfig_additions() const; - virtual void device_config_complete() { m_shortname = "isa_fdc_smc"; } }; +class isa8_fdc_superio_device : public isa8_fdc_device { +public: + isa8_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + virtual machine_config_constructor device_mconfig_additions() const; +}; // device type definition +extern const device_type ISA8_FDC_XT; +extern const device_type ISA8_FDC_AT; extern const device_type ISA8_FDC_SMC; +extern const device_type ISA8_FDC_PS2; +extern const device_type ISA8_FDC_SUPERIO; #endif /* ISA_FDC_H */ diff --git a/src/mess/machine/kc_d004.c b/src/mess/machine/kc_d004.c index e570f19bd9b..6e5ab7b7c24 100644 --- a/src/mess/machine/kc_d004.c +++ b/src/mess/machine/kc_d004.c @@ -8,6 +8,8 @@ #include "emu.h" #include "kc_d004.h" +#include "formats/mfi_dsk.h" +#include "formats/kc85_dsk.h" #define Z80_TAG "disk" #define Z80CTC_TAG "z80ctc" @@ -26,9 +28,8 @@ ADDRESS_MAP_END static ADDRESS_MAP_START(kc_d004_io, AS_IO, 8, kc_d004_device) ADDRESS_MAP_UNMAP_HIGH ADDRESS_MAP_GLOBAL_MASK(0xff) - AM_RANGE(0xf0, 0xf0) AM_DEVREAD_LEGACY(UPD765_TAG, upd765_status_r) - AM_RANGE(0xf1, 0xf1) AM_DEVREADWRITE_LEGACY(UPD765_TAG, upd765_data_r, upd765_data_w) - AM_RANGE(0xf2, 0xf3) AM_DEVREADWRITE_LEGACY(UPD765_TAG, upd765_dack_r, upd765_dack_w) + AM_RANGE(0xf0, 0xf1) AM_DEVICE(UPD765_TAG, upd765a_device, map) + AM_RANGE(0xf2, 0xf3) AM_DEVREADWRITE(UPD765_TAG, upd765a_device, mdma_r, mdma_w) AM_RANGE(0xf4, 0xf4) AM_READ(hw_input_gate_r) AM_RANGE(0xf6, 0xf7) AM_WRITE(fdd_select_w) AM_RANGE(0xf8, 0xf9) AM_WRITE(hw_terminal_count_w) @@ -37,9 +38,8 @@ ADDRESS_MAP_END static ADDRESS_MAP_START(kc_d004_gide_io, AS_IO, 8, kc_d004_gide_device) ADDRESS_MAP_UNMAP_HIGH - AM_RANGE(0x00f0, 0x00f0) AM_MIRROR(0xff00) AM_DEVREAD_LEGACY(UPD765_TAG, upd765_status_r) - AM_RANGE(0x00f1, 0x00f1) AM_MIRROR(0xff00) AM_DEVREADWRITE_LEGACY(UPD765_TAG, upd765_data_r, upd765_data_w) - AM_RANGE(0x00f2, 0x00f3) AM_MIRROR(0xff00) AM_DEVREADWRITE_LEGACY(UPD765_TAG, upd765_dack_r, upd765_dack_w) + AM_RANGE(0x00f0, 0x00f1) AM_MIRROR(0xff00) AM_DEVICE(UPD765_TAG, upd765a_device, map) + AM_RANGE(0x00f2, 0x00f3) AM_MIRROR(0xff00) AM_DEVREADWRITE(UPD765_TAG, upd765a_device, mdma_r, mdma_w) AM_RANGE(0x00f4, 0x00f4) AM_MIRROR(0xff00) AM_READ(hw_input_gate_r) AM_RANGE(0x00f6, 0x00f7) AM_MIRROR(0xff00) AM_WRITE(fdd_select_w) AM_RANGE(0x00f8, 0x00f9) AM_MIRROR(0xff00) AM_WRITE(hw_terminal_count_w) @@ -47,54 +47,15 @@ static ADDRESS_MAP_START(kc_d004_gide_io, AS_IO, 8, kc_d004_gide_device) AM_RANGE(0x0000, 0xffff) AM_READWRITE(gide_r, gide_w) ADDRESS_MAP_END -static LEGACY_FLOPPY_OPTIONS_START(kc_d004) - LEGACY_FLOPPY_OPTION(kc85, "img", "KC85 disk image 800KB", basicdsk_identify_default, basicdsk_construct_default, NULL, - HEADS([2]) - TRACKS([80]) - SECTORS([5]) - SECTOR_LENGTH([1024]) - FIRST_SECTOR_ID([1])) - LEGACY_FLOPPY_OPTION(kc85, "img", "KC85 disk image 720KB", basicdsk_identify_default, basicdsk_construct_default, NULL, - HEADS([2]) - TRACKS([80]) - SECTORS([9]) - SECTOR_LENGTH([512]) - FIRST_SECTOR_ID([1])) - LEGACY_FLOPPY_OPTION(kc85, "img", "KC85 disk image 640KB", basicdsk_identify_default, basicdsk_construct_default, NULL, - HEADS([2]) - TRACKS([80]) - SECTORS([16]) - SECTOR_LENGTH([256]) - FIRST_SECTOR_ID([1])) -LEGACY_FLOPPY_OPTIONS_END - -static const floppy_interface kc_d004_floppy_interface = -{ - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - FLOPPY_STANDARD_5_25_DSHD, - LEGACY_FLOPPY_OPTIONS_NAME(kc_d004), - "floppy_5_25", +static const floppy_format_type kc_d004_floppy_formats[] = { + FLOPPY_KC85_FORMAT, + FLOPPY_MFI_FORMAT, NULL }; -static device_t *kc_d004_get_fdd(device_t *device, int floppy_index) -{ - kc_d004_device* owner = dynamic_cast<kc_d004_device *>(device->owner()); - return owner->get_active_fdd(); -} - -static const upd765_interface kc_d004_interface = -{ - DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, kc_d004_device, fdc_interrupt), - DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, kc_d004_device, fdc_dma_request), - kc_d004_get_fdd, - UPD765_RDY_PIN_NOT_CONNECTED, - {FLOPPY_0, FLOPPY_1, FLOPPY_2, FLOPPY_3} -}; +static SLOT_INTERFACE_START( kc_d004_floppies ) + SLOT_INTERFACE( "525hd", FLOPPY_525_HD ) +SLOT_INTERFACE_END static const z80_daisy_config kc_d004_daisy_chain[] = { @@ -118,8 +79,11 @@ static MACHINE_CONFIG_FRAGMENT(kc_d004) MCFG_Z80CTC_ADD( Z80CTC_TAG, XTAL_8MHz/2, kc_d004_ctc_intf ) - MCFG_UPD765A_ADD(UPD765_TAG, kc_d004_interface) - MCFG_LEGACY_FLOPPY_4_DRIVES_ADD(kc_d004_floppy_interface) + MCFG_UPD765A_ADD(UPD765_TAG, false, false) + MCFG_FLOPPY_DRIVE_ADD(UPD765_TAG ":0", kc_d004_floppies, "525hd", 0, kc_d004_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(UPD765_TAG ":1", kc_d004_floppies, "525hd", 0, kc_d004_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(UPD765_TAG ":2", kc_d004_floppies, "525hd", 0, kc_d004_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD(UPD765_TAG ":3", kc_d004_floppies, "525hd", 0, kc_d004_floppy_formats) MACHINE_CONFIG_END static const ide_config ide_intf = @@ -202,6 +166,9 @@ void kc_d004_device::device_start() m_reset_timer = timer_alloc(TIMER_RESET); m_tc_clear_timer = timer_alloc(TIMER_TC_CLEAR); + + m_fdc->setup_intrq_cb(upd765a_device::line_cb(FUNC(kc_d004_device::fdc_irq), this)); + m_fdc->setup_drq_cb(upd765a_device::line_cb(FUNC(kc_d004_device::fdc_drq), this)); } //------------------------------------------------- @@ -212,7 +179,7 @@ void kc_d004_device::device_reset() { m_rom_base = 0xc000; m_enabled = m_connected = 0; - m_floppy = downcast<device_t *>(subdevice(FLOPPY_0)); + m_floppy = subdevice<floppy_connector>(UPD765_TAG ":0")->get_device(); // hold cpu at reset m_reset_timer->adjust(attotime::zero); @@ -248,7 +215,7 @@ void kc_d004_device::device_timer(emu_timer &timer, device_timer_id id, int para m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); break; case TIMER_TC_CLEAR: - upd765_tc_w(m_fdc, 0x00); + m_fdc->tc_w(false); break; } } @@ -369,12 +336,12 @@ READ8_MEMBER(kc_d004_device::hw_input_gate_r) */ - if (floppy_ready_r(m_floppy)) + if (m_floppy->ready_r()) m_hw_input_gate |= 0x20; else m_hw_input_gate &= ~0x20; - if (floppy_index_r(m_floppy)) + if (m_floppy->idx_r()) m_hw_input_gate &= ~0x10; else m_hw_input_gate |= 0x10; @@ -385,23 +352,26 @@ READ8_MEMBER(kc_d004_device::hw_input_gate_r) WRITE8_MEMBER(kc_d004_device::fdd_select_w) { if (data & 0x01) - m_floppy = downcast<device_t *>(subdevice(FLOPPY_0)); + m_floppy = subdevice<floppy_connector>(UPD765_TAG ":0")->get_device(); else if (data & 0x02) - m_floppy = downcast<device_t *>(subdevice(FLOPPY_1)); + m_floppy = subdevice<floppy_connector>(UPD765_TAG ":1")->get_device(); else if (data & 0x04) - m_floppy = downcast<device_t *>(subdevice(FLOPPY_2)); + m_floppy = subdevice<floppy_connector>(UPD765_TAG ":2")->get_device(); else if (data & 0x08) - m_floppy = downcast<device_t *>(subdevice(FLOPPY_3)); + m_floppy = subdevice<floppy_connector>(UPD765_TAG ":3")->get_device(); + else + m_floppy = NULL; + m_fdc->set_floppy(m_floppy); } WRITE8_MEMBER(kc_d004_device::hw_terminal_count_w) { - upd765_tc_w(m_fdc, 1); + m_fdc->tc_w(false); m_tc_clear_timer->adjust(attotime::from_nsec(200)); } -WRITE_LINE_MEMBER( kc_d004_device::fdc_interrupt ) +void kc_d004_device::fdc_irq(bool state) { if (state) m_hw_input_gate &= ~0x40; @@ -409,7 +379,7 @@ WRITE_LINE_MEMBER( kc_d004_device::fdc_interrupt ) m_hw_input_gate |= 0x40; } -WRITE_LINE_MEMBER( kc_d004_device::fdc_dma_request ) +void kc_d004_device::fdc_drq(bool state) { if (state) m_hw_input_gate &= ~0x80; diff --git a/src/mess/machine/kc_d004.h b/src/mess/machine/kc_d004.h index 7d4640c4c2f..b7b376ee0dd 100644 --- a/src/mess/machine/kc_d004.h +++ b/src/mess/machine/kc_d004.h @@ -48,19 +48,19 @@ protected: virtual void io_write(offs_t offset, UINT8 data); public: - device_t* get_active_fdd() { return m_floppy; } DECLARE_READ8_MEMBER(hw_input_gate_r); DECLARE_WRITE8_MEMBER(fdd_select_w); DECLARE_WRITE8_MEMBER(hw_terminal_count_w); - DECLARE_WRITE_LINE_MEMBER(fdc_interrupt); - DECLARE_WRITE_LINE_MEMBER(fdc_dma_request); + + void fdc_irq(bool state); + void fdc_drq(bool state); private: static const device_timer_id TIMER_RESET = 0; static const device_timer_id TIMER_TC_CLEAR = 1; required_device<cpu_device> m_cpu; - required_device<device_t> m_fdc; + required_device<upd765a_device> m_fdc; required_shared_ptr<UINT8> m_koppel_ram; // internal state @@ -73,7 +73,8 @@ private: UINT8 m_enabled; UINT8 m_connected; UINT8 m_active_fdd; - device_t * m_floppy; + + floppy_image_device *m_floppy; }; diff --git a/src/mess/machine/n82077aa.c b/src/mess/machine/n82077aa.c deleted file mode 100644 index 5f7f96599f1..00000000000 --- a/src/mess/machine/n82077aa.c +++ /dev/null @@ -1,1212 +0,0 @@ - -#include "n82077aa.h" - -const device_type N82077AA = &device_creator<n82077aa_device>; - -DEVICE_ADDRESS_MAP_START(amap, 8, n82077aa_device) - AM_RANGE(0x0, 0x0) AM_READ(sra_r) - AM_RANGE(0x1, 0x1) AM_READ(srb_r) - AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) - AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) - AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) - AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) - AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) -ADDRESS_MAP_END - -int n82077aa_device::rates[4] = { 500000, 300000, 250000, 1000000 }; - -n82077aa_device::n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, N82077AA, "N82077AA", tag, owner, clock) -{ -} - -void n82077aa_device::set_mode(int _mode) -{ - mode = _mode; -} - -void n82077aa_device::setup_intrq_cb(line_cb cb) -{ - intrq_cb = cb; -} - -void n82077aa_device::setup_drq_cb(line_cb cb) -{ - drq_cb = cb; -} - -void n82077aa_device::device_start() -{ - static const char *names[] = { "fd0", "fd1", "fd2", "fd3" }; - for(int i=0; i != 4; i++) { - flopi[i].tm = timer_alloc(i); - flopi[i].id = i; - floppy_connector *con = machine().device<floppy_connector>(names[i]); - if(con) { - flopi[i].dev = con->get_device(); - flopi[i].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(n82077aa_device::index_callback), this)); - } else - flopi[i].dev = 0; - } -} - -void n82077aa_device::device_reset() -{ - main_phase = PHASE_CMD; - for(int i=0; i<4; i++) { - flopi[i].main_state = IDLE; - flopi[i].sub_state = IDLE; - flopi[i].irq = false; - flopi[i].live = false; - } - data_irq = false; - dor = 0x00; - fifo_pos = 0; - command_pos = 0; - result_pos = 0; - fifocfg = 0x10; - cur_live.fi = 0; - cur_irq = false; - drq = false; - live_abort(); -} - -READ8_MEMBER(n82077aa_device::sra_r) -{ - UINT8 sra = 0; - int fid = dor & 3; - floppy_info &fi = flopi[fid]; - if(fi.dir) - sra |= 0x01; - if(fi.index) - sra |= 0x04; - if((dsr & 3) == 0 || (dsr & 3) == 3) - sra |= 0x08; - if(fi.dev && fi.dev->trk00_r()) - sra |= 0x10; - if(fi.main_state == SEEK_WAIT_STEP_SIGNAL_TIME) - sra |= 0x20; - sra |= 0x40; - if(cur_irq) - sra |= 0x80; - if(mode == MODE_M30) - sra ^= 0x1f; - return sra; -} - -READ8_MEMBER(n82077aa_device::srb_r) -{ - return 0; -} - -READ8_MEMBER(n82077aa_device::dor_r) -{ - return dor; -} - -WRITE8_MEMBER(n82077aa_device::dor_w) -{ - UINT8 diff = dor ^ data; - dor = data; - if((diff & 4) && !(data & 4)) - device_reset(); - else - for(int i=0; i<4; i++) { - floppy_info &fi = flopi[i]; - if(fi.dev && (diff & (0x10 << i))) - fi.dev->mon_w(!(dor & (0x10 << i))); - } - -} - -READ8_MEMBER(n82077aa_device::tdr_r) -{ - return 0; -} - -WRITE8_MEMBER(n82077aa_device::tdr_w) -{ -} - -READ8_MEMBER(n82077aa_device::msr_r) -{ - UINT32 msr = 0; - switch(main_phase) { - case PHASE_CMD: - msr |= 0x80; - if(command_pos) - msr |= 0x10; - break; - case PHASE_EXEC: - msr |= 0x10; - break; - - case PHASE_RESULT: - msr |= 0xd0; - break; - } - for(int i=0; i<4; i++) - if(flopi[i].main_state == RECALIBRATE || flopi[i].main_state == SEEK) - msr |= 1<<i; - - if(data_irq) { - data_irq = false; - check_irq(); - } - - return msr; -} - -WRITE8_MEMBER(n82077aa_device::dsr_w) -{ - dsr = data; -} - -READ8_MEMBER(n82077aa_device::fifo_r) -{ - UINT8 r = 0; - switch(main_phase) { - case PHASE_RESULT: - r = result[0]; - result_pos--; - memmove(result, result+1, result_pos); - if(!result_pos) - main_phase = PHASE_CMD; - break; - default: - logerror("%s: fifo_r in phase %d\n", tag(), main_phase); - // exit(1); - } - - return r; -} - -WRITE8_MEMBER(n82077aa_device::fifo_w) -{ - switch(main_phase) { - case PHASE_CMD: { - command[command_pos++] = data; - int cmd = check_command(); - if(cmd == C_INCOMPLETE) - break; - if(cmd == C_INVALID) { - logerror("%s: Invalid on %02x\n", tag(), command[0]); - exit(1); - command_pos = 0; - return; - } - start_command(cmd); - break; - } - default: - logerror("%s: fifo_w in phase %d\n", tag(), main_phase); - exit(1); - } -} - -READ8_MEMBER(n82077aa_device::dir_r) -{ - return 0x78; -} - -WRITE8_MEMBER(n82077aa_device::ccr_w) -{ - dsr = (dsr & 0xfc) | (data & 3); -} - -void n82077aa_device::set_drq(bool state) -{ - if(state != drq) { - drq = state; - if(!drq_cb.isnull()) - drq_cb(drq); - } -} - -bool n82077aa_device::get_drq() const -{ - return drq; -} - -void n82077aa_device::fifo_push(UINT8 data) -{ - if(fifo_pos == 16) { - logerror("%s: Overflow\n", tag()); - return; - } - fifo[fifo_pos++] = data; - fifo_expected--; - if(!drq) { - int thr = (fifocfg & 15)+1; - if(!fifo_expected || fifo_pos >= thr || (fifocfg & 0x20)) - set_drq(true); - } -} - -void n82077aa_device::fifo_expect(int size, bool write) -{ - fifo_expected = size; - fifo_write = write; -} - -UINT8 n82077aa_device::dma_r() -{ - if(!fifo_pos) - return 0; - UINT8 r = fifo[0]; - fifo_pos--; - memmove(fifo, fifo+1, fifo_pos); - if(!fifo_pos) - set_drq(false); - return r; -} - -void n82077aa_device::live_start(floppy_info &fi, int state) -{ - cur_live.tm = machine().time(); - cur_live.state = state; - cur_live.next_state = -1; - cur_live.fi = &fi; - cur_live.shift_reg = 0; - cur_live.crc = 0xffff; - cur_live.bit_counter = 0; - cur_live.data_separator_phase = false; - cur_live.data_reg = 0; - cur_live.previous_type = live_info::PT_NONE; - cur_live.data_bit_context = false; - cur_live.byte_counter = 0; - cur_live.pll.reset(cur_live.tm); - cur_live.pll.set_clock(attotime::from_hz(rates[dsr & 3]*2)); - checkpoint_live = cur_live; - fi.live = true; - - live_run(); -} - -void n82077aa_device::checkpoint() -{ - if(cur_live.fi) - cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); - checkpoint_live = cur_live; -} - -void n82077aa_device::rollback() -{ - cur_live = checkpoint_live; -} - -void n82077aa_device::live_delay(int state) -{ - cur_live.next_state = state; - if(cur_live.tm != machine().time()) - cur_live.fi->tm->adjust(cur_live.tm - machine().time()); -} - -void n82077aa_device::live_sync() -{ - if(!cur_live.tm.is_never()) { - if(cur_live.tm > machine().time()) { - rollback(); - live_run(machine().time()); - cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); - } - if(cur_live.tm == machine().time()) { - cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); - if(cur_live.next_state != -1) { - cur_live.state = cur_live.next_state; - cur_live.next_state = -1; - } - if(cur_live.state == IDLE) { - cur_live.tm = attotime::never; - cur_live.fi->live = false; - cur_live.fi = 0; - } - } - cur_live.next_state = -1; - checkpoint(); - } -} - -void n82077aa_device::live_abort() -{ - - if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { - rollback(); - live_run(machine().time()); - } - - if(cur_live.fi) { - cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); - cur_live.fi->live = false; - cur_live.fi = 0; - } - - cur_live.tm = attotime::never; - cur_live.state = IDLE; - cur_live.next_state = -1; -} - -void n82077aa_device::live_run(attotime limit) -{ - if(cur_live.state == IDLE || cur_live.next_state != -1) - return; - - if(limit == attotime::never) { - if(cur_live.fi->dev) - limit = cur_live.fi->dev->time_next_index(); - if(limit == attotime::never) { - // Happens when there's no disk or if the fdc is not - // connected to a drive, hence no index pulse. Force a - // sync from time to time in that case, so that the main - // cpu timeout isn't too painful. Avoids looping into - // infinity looking for data too. - - limit = machine().time() + attotime::from_msec(1); - cur_live.fi->tm->adjust(attotime::from_msec(1)); - } - } - - for(;;) { - switch(cur_live.state) { - case SEARCH_ADDRESS_MARK_HEADER: - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter); -#endif - - if(cur_live.shift_reg == 0x4489) { - cur_live.crc = 0x443b; - cur_live.data_separator_phase = false; - cur_live.bit_counter = 0; - cur_live.state = READ_HEADER_BLOCK_HEADER; - } - break; - - case READ_HEADER_BLOCK_HEADER: { - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter); -#endif - if(cur_live.bit_counter & 15) - break; - - int slot = cur_live.bit_counter >> 4; - - if(slot < 3) { - if(cur_live.shift_reg != 0x4489) - cur_live.state = SEARCH_ADDRESS_MARK_HEADER; - break; - } - if(cur_live.data_reg != 0xfe) { - cur_live.state = SEARCH_ADDRESS_MARK_HEADER; - break; - } - - cur_live.bit_counter = 0; - cur_live.state = READ_ID_BLOCK_TO_LOCAL; - - break; - } - - case READ_ID_BLOCK_TO_LOCAL: { - if(read_one_bit(limit)) - return; - if(cur_live.bit_counter & 15) - break; - int slot = (cur_live.bit_counter >> 4)-1; - cur_live.idbuf[slot] = cur_live.data_reg; - if(slot == 5) { - live_delay(IDLE); - return; - } - break; - } - - case SEARCH_ADDRESS_MARK_DATA: - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter >> 4, cur_live.bit_counter & 15); -#endif - if(cur_live.bit_counter > 43*16) { - live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); - return; - } - - if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg == 0x4489) { - cur_live.crc = 0x443b; - cur_live.data_separator_phase = false; - cur_live.bit_counter = 0; - cur_live.state = READ_DATA_BLOCK_HEADER; - } - break; - - case READ_DATA_BLOCK_HEADER: { - if(read_one_bit(limit)) - return; -#if 0 - fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, - (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | - (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | - (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | - (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | - (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | - (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | - (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | - (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), - cur_live.bit_counter); -#endif - if(cur_live.bit_counter & 15) - break; - - int slot = cur_live.bit_counter >> 4; - - if(slot < 3) { - if(cur_live.shift_reg != 0x4489) { - live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); - return; - } - break; - } - if(cur_live.data_reg != 0xfb && cur_live.data_reg != 0xfd) { - live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); - return; - } - - cur_live.bit_counter = 0; - cur_live.state = READ_SECTOR_DATA; - break; - } - - case SEARCH_ADDRESS_MARK_DATA_FAILED: - // status |= S_RNF; - cur_live.state = IDLE; - return; - - case READ_SECTOR_DATA: { - if(read_one_bit(limit)) - return; - if(cur_live.bit_counter & 15) - break; - int slot = (cur_live.bit_counter >> 4)-1; - if(slot < sector_size) { - // Sector data - live_delay(READ_SECTOR_DATA_BYTE); - return; - - } else if(slot < sector_size+2) { - // CRC - if(slot == sector_size+1) { - live_delay(IDLE); - return; - } - } - - break; - } - - case READ_SECTOR_DATA_BYTE: - fifo_push(cur_live.data_reg); - cur_live.state = READ_SECTOR_DATA; - checkpoint(); - break; - - default: - logerror("%s: Unknown live state %d\n", tts(cur_live.tm).cstr(), cur_live.state); - return; - } - } -} - -int n82077aa_device::check_command() -{ - // 0.000010 read track - // 00000011 specify - // 00000100 sense drive status - // ..000101 write data - // ...00110 read data - // 00000111 recalibrate - // 00001000 sense interrupt status - // ..001001 write deleted data - // 0.001010 read id - // ...01100 read deleted data - // 0.001101 format track - // 00001110 dumpreg - // 00001111 seek - // 00010000 version - // ...10001 scan equal - // 00010010 perpendicular mode - // 00010011 configure - // .0010100 lock - // ...10110 verify - // ...11001 scan low or equal - // ...11101 scan high or equal - // 1.001111 relative seek - - switch(command[0]) { - case 0x03: - return command_pos == 3 ? C_SPECIFY : C_INCOMPLETE; - - case 0x06: case 0x26: case 0x46: case 0x66: case 0x86: case 0xa6: case 0xc6: case 0xe6: - return command_pos == 9 ? C_READ_DATA : C_INCOMPLETE; - - case 0x07: - return command_pos == 2 ? C_RECALIBRATE : C_INCOMPLETE; - - case 0x08: - return C_SENSE_INTERRUPT_STATUS; - - case 0x0a: case 0x4a: - return command_pos == 2 ? C_READ_ID : C_INCOMPLETE; - - case 0x0f: - return command_pos == 3 ? C_SEEK : C_INCOMPLETE; - - case 0x12: - return command_pos == 2 ? C_PERPENDICULAR : C_INCOMPLETE; - - case 0x13: - return command_pos == 4 ? C_CONFIGURE : C_INCOMPLETE; - - default: - return C_INVALID; - } -} - -void n82077aa_device::start_command(int cmd) -{ - command_pos = 0; - result_pos = 0; - main_phase = PHASE_EXEC; - switch(cmd) { - case C_CONFIGURE: - logerror("%s: command configure %02x %02x %02x\n", - tag(), - command[1], command[2], command[3]); - // byte 1 is ignored, byte 3 is precompensation-related - fifocfg = command[2]; - main_phase = PHASE_CMD; - break; - - case C_PERPENDICULAR: - logerror("%s: command perpendicular\n", tag()); - main_phase = PHASE_CMD; - break; - - case C_READ_DATA: - read_data_start(flopi[command[1] & 3]); - break; - - case C_READ_ID: - read_id_start(flopi[command[1] & 3]); - break; - - case C_RECALIBRATE: - recalibrate_start(flopi[command[1] & 3]); - main_phase = PHASE_CMD; - break; - - case C_SEEK: - seek_start(flopi[command[1] & 3]); - main_phase = PHASE_CMD; - break; - - case C_SENSE_INTERRUPT_STATUS: { - logerror("%s: command sense interrupt status\n", tag()); - main_phase = PHASE_RESULT; - - int fid; - for(fid=0; fid<4 && !flopi[fid].irq; fid++); - if(fid == 4) { - result[0] = 0x80; - result_pos = 1; - break; - } - floppy_info &fi = flopi[fid]; - fi.irq = false; - result[0] = (fi.status << 6) | 0x20 | fid; - result[1] = fi.pcn; - result_pos = 2; - check_irq(); - break; - } - - case C_SPECIFY: - logerror("%s command specify %02x %02x\n", - tag(), - command[1], command[2]); - spec = (command[1] << 8) | command[2]; - main_phase = PHASE_CMD; - break; - - default: - fprintf(stderr, "start command %d\n", cmd); - exit(1); - } -} - -void n82077aa_device::command_end(floppy_info &fi, bool data_completion, int status) -{ - fi.main_state = fi.sub_state = IDLE; - if(data_completion) - data_irq = true; - else - fi.irq = true; - fi.status = status; - check_irq(); -} - -void n82077aa_device::recalibrate_start(floppy_info &fi) -{ - logerror("%s: command recalibrate\n", tag()); - fi.main_state = RECALIBRATE; - fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; - fi.dir = 1; - seek_continue(fi); -} - -void n82077aa_device::seek_start(floppy_info &fi) -{ - logerror("%s: command seek %d\n", tag(), command[2]); - fi.main_state = SEEK; - fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; - fi.dir = fi.pcn > command[2] ? 1 : 0; - seek_continue(fi); -} - -void n82077aa_device::delay_cycles(emu_timer *tm, int cycles) -{ - tm->adjust(attotime::from_double(double(cycles)/rates[dsr & 3])); -} - -void n82077aa_device::seek_continue(floppy_info &fi) -{ - for(;;) { - switch(fi.sub_state) { - case SEEK_MOVE: - if(fi.dev) { - fi.dev->dir_w(fi.dir); - fi.dev->stp_w(0); - } - fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; - fi.tm->adjust(attotime::from_nsec(2500)); - return; - - case SEEK_WAIT_STEP_SIGNAL_TIME: - return; - - case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: - if(fi.dev) - fi.dev->stp_w(1); - - if(fi.main_state == SEEK) { - if(fi.pcn > command[2]) - fi.pcn--; - else - fi.pcn++; - } - fi.sub_state = SEEK_WAIT_STEP_TIME; - delay_cycles(fi.tm, 500*(16-(spec >> 12))); - return; - - case SEEK_WAIT_STEP_TIME: - return; - - case SEEK_WAIT_STEP_TIME_DONE: { - bool done = false; - switch(fi.main_state) { - case RECALIBRATE: - done = !fi.dev || !fi.dev->trk00_r(); - if(done) - fi.pcn = 0; - break; - case SEEK: - done = fi.pcn == command[2]; - break; - } - if(done) { - command_end(fi, false, 0); - return; - } - fi.sub_state = SEEK_MOVE; - break; - } - } - } -} - -void n82077aa_device::read_data_start(floppy_info &fi) -{ - fi.main_state = READ_DATA; - fi.sub_state = HEAD_LOAD_DONE; - - logerror("%s: command read data%s%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", - tag(), - command[0] & 0x80 ? " mt" : "", - command[0] & 0x40 ? " mfm" : "", - command[0] & 0x20 ? " sk" : "", - command[0], - command[1], - command[2], - command[3], - command[4], - 128 << (command[5] & 7), - command[6], - command[7], - command[8], - rates[dsr & 3]); - - if(fi.dev) - fi.dev->ss_w(command[1] & 4 ? 1 : 0); - read_data_continue(fi); -} - -void n82077aa_device::read_data_continue(floppy_info &fi) -{ - for(;;) { - switch(fi.sub_state) { - case HEAD_LOAD_DONE: - if(fi.pcn == command[2] || !(fifocfg & 0x40)) { - fi.sub_state = SEEK_DONE; - break; - } - if(fi.dev) { - fi.dev->dir_w(fi.pcn > command[2] ? 1 : 0); - fi.dev->stp_w(0); - } - fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; - fi.tm->adjust(attotime::from_nsec(2500)); - return; - - case SEEK_WAIT_STEP_SIGNAL_TIME: - return; - - case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: - if(fi.dev) - fi.dev->stp_w(1); - - fi.sub_state = SEEK_WAIT_STEP_TIME; - delay_cycles(fi.tm, 500*(16-(spec >> 12))); - return; - - case SEEK_WAIT_STEP_TIME: - return; - - case SEEK_WAIT_STEP_TIME_DONE: - if(fi.pcn > command[2]) - fi.pcn--; - else - fi.pcn++; - fi.sub_state = HEAD_LOAD_DONE; - break; - - case SEEK_DONE: - counter = 0; - fi.sub_state = SCAN_ID; - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - - case SCAN_ID: - if(!sector_matches()) { - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - } - if(cur_live.crc) { - fprintf(stderr, "Header CRC error\n"); - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - } - sector_size = 128 << (cur_live.idbuf[3] & 3); - fifo_expect(sector_size, false); - fi.sub_state = SECTOR_READ; - live_start(fi, SEARCH_ADDRESS_MARK_DATA); - return; - - case SCAN_ID_FAILED: - fprintf(stderr, "RNF\n"); - command_end(fi, true, 1); - return; - - case SECTOR_READ: - if(cur_live.crc) { - fprintf(stderr, "CRC error\n"); - } - if(command[4] < command[6]) { - command[4]++; - fi.sub_state = HEAD_LOAD_DONE; - break; - } - - main_phase = PHASE_RESULT; - result[0] = 0; - result[1] = 0; - result[2] = 0; - result[3] = command[2]; - result[4] = command[3]; - result[5] = command[4]; - result[6] = command[5]; - result_pos = 7; - command_end(fi, true, 0); - return; - - default: - logerror("%s: read sector unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); - return; - } - } -} - -void n82077aa_device::read_id_start(floppy_info &fi) -{ - fi.main_state = READ_DATA; - fi.sub_state = HEAD_LOAD_DONE; - - logerror("%s: command read id%s, rate=%d\n", - tag(), - command[0] & 0x40 ? " mfm" : "", - rates[dsr & 3]); - - if(fi.dev) - fi.dev->ss_w(command[1] & 4 ? 1 : 0); - read_id_continue(fi); -} - -void n82077aa_device::read_id_continue(floppy_info &fi) -{ - for(;;) { - switch(fi.sub_state) { - case HEAD_LOAD_DONE: - counter = 0; - fi.sub_state = SCAN_ID; - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - - case SCAN_ID: - if(cur_live.crc) { - fprintf(stderr, "Header CRC error\n"); - live_start(fi, SEARCH_ADDRESS_MARK_HEADER); - return; - } - - main_phase = PHASE_RESULT; - result[0] = 0; - result[1] = 0; - result[2] = 0; - result[3] = cur_live.idbuf[0]; - result[4] = cur_live.idbuf[1]; - result[5] = cur_live.idbuf[2]; - result[6] = cur_live.idbuf[3]; - result_pos = 7; - command_end(fi, true, 0); - return; - - default: - logerror("%s: read id unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); - return; - } - } -} - -void n82077aa_device::check_irq() -{ - bool old_irq = cur_irq; - cur_irq = data_irq; - for(int i=0; i<4; i++) - cur_irq = cur_irq || flopi[i].irq; - if(cur_irq != old_irq && !intrq_cb.isnull()) - intrq_cb(cur_irq); -} - -astring n82077aa_device::tts(attotime t) -{ - char buf[256]; - int nsec = t.attoseconds / ATTOSECONDS_PER_NANOSECOND; - sprintf(buf, "%4d.%03d,%03d,%03d", int(t.seconds), nsec/1000000, (nsec/1000)%1000, nsec % 1000); - return buf; -} - -astring n82077aa_device::ttsn() -{ - return tts(machine().time()); -} - -void n82077aa_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) -{ - live_sync(); - - floppy_info &fi = flopi[id]; - switch(fi.sub_state) { - case SEEK_WAIT_STEP_SIGNAL_TIME: - fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME_DONE; - break; - case SEEK_WAIT_STEP_TIME: - fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; - break; - } - - general_continue(fi); -} - -void n82077aa_device::index_callback(floppy_image_device *floppy, int state) -{ - int fid; - for(fid=0; fid<4; fid++) - if(flopi[fid].dev == floppy) - break; - - assert(fid != 4); - floppy_info &fi = flopi[fid]; - - live_sync(); - fi.index = state; - - if(!state) { - general_continue(fi); - return; - } - - switch(fi.sub_state) { - case IDLE: - case SEEK_MOVE: - case SEEK_WAIT_STEP_SIGNAL_TIME: - case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: - case SEEK_WAIT_STEP_TIME: - case SEEK_WAIT_STEP_TIME_DONE: - case HEAD_LOAD_DONE: - case SCAN_ID_FAILED: - case SECTOR_READ: - break; - - case SCAN_ID: - counter++; - if(counter == 2) - fi.sub_state = SCAN_ID_FAILED; - break; - - default: - logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); - break; - } - - general_continue(fi); -} - - -void n82077aa_device::general_continue(floppy_info &fi) -{ - if(fi.live && cur_live.state != IDLE) { - live_run(); - if(cur_live.state != IDLE) - return; - } - - switch(fi.main_state) { - case IDLE: - break; - - case RECALIBRATE: - case SEEK: - seek_continue(fi); - break; - - case READ_DATA: - read_data_continue(fi); - break; - - case READ_ID: - read_id_continue(fi); - break; - - default: - logerror("%s: general_continue on unknown main-state %d\n", ttsn().cstr(), fi.main_state); - break; - } -} - -bool n82077aa_device::read_one_bit(attotime limit) -{ - int bit = cur_live.pll.get_next_bit(cur_live.tm, cur_live.fi->dev, limit); - if(bit < 0) - return true; - cur_live.shift_reg = (cur_live.shift_reg << 1) | bit; - cur_live.bit_counter++; - if(cur_live.data_separator_phase) { - cur_live.data_reg = (cur_live.data_reg << 1) | bit; - if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) - cur_live.crc = (cur_live.crc << 1) ^ 0x1021; - else - cur_live.crc = cur_live.crc << 1; - } - cur_live.data_separator_phase = !cur_live.data_separator_phase; - return false; -} - -bool n82077aa_device::write_one_bit(attotime limit) -{ - bool bit = cur_live.shift_reg & 0x8000; - if(cur_live.pll.write_next_bit(bit, cur_live.tm, cur_live.fi->dev, limit)) - return true; - if(cur_live.bit_counter & 1) { - if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) - cur_live.crc = (cur_live.crc << 1) ^ 0x1021; - else - cur_live.crc = cur_live.crc << 1; - } - cur_live.shift_reg = cur_live.shift_reg << 1; - cur_live.bit_counter--; - return false; -} - -bool n82077aa_device::sector_matches() const -{ - return - cur_live.idbuf[0] == command[2] && - cur_live.idbuf[1] == command[3] && - cur_live.idbuf[2] == command[4] && - cur_live.idbuf[3] == command[5]; -} - -void n82077aa_device::pll_t::set_clock(attotime _period) -{ - period = _period; - period_adjust_base = period * 0.05; - min_period = period * 0.75; - max_period = period * 1.25; -} - -void n82077aa_device::pll_t::reset(attotime when) -{ - ctime = when; - phase_adjust = attotime::zero; - freq_hist = 0; - write_position = 0; - write_start_time = attotime::never; -} - -void n82077aa_device::pll_t::start_writing(attotime tm) -{ - write_start_time = tm; - write_position = 0; -} - -void n82077aa_device::pll_t::stop_writing(floppy_image_device *floppy, attotime tm) -{ - commit(floppy, tm); - write_start_time = attotime::never; -} - -void n82077aa_device::pll_t::commit(floppy_image_device *floppy, attotime tm) -{ - if(write_start_time.is_never() || tm == write_start_time) - return; - - if(floppy) - floppy->write_flux(write_start_time, tm, write_position, write_buffer); - write_start_time = tm; - write_position = 0; -} - -int n82077aa_device::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit) -{ - attotime edge = floppy ? floppy->get_next_transition(ctime) : attotime::never; - - attotime next = ctime + period + phase_adjust; - -#if 0 - if(!edge.is_never()) - fprintf(stderr, "transition_time=%s, next=%s\n", tts(edge).cstr(), tts(next).cstr()); -#endif - - if(next > limit) - return -1; - - ctime = next; - - if(edge.is_never() || edge >= next) { - // No transition in the window means 0 and pll in free run mode - phase_adjust = attotime::zero; - tm = next; - return 0; - } - - // Transition in the window means 1, and the pll is adjusted - - attotime delta = edge - (next - period/2); - - phase_adjust = 0.65*delta; - - if(delta < attotime::zero) { - if(freq_hist < 0) - freq_hist--; - else - freq_hist = -1; - } else if(delta > attotime::zero) { - if(freq_hist > 0) - freq_hist++; - else - freq_hist = 1; - } else - freq_hist = 0; - - if(freq_hist) { - int afh = freq_hist < 0 ? -freq_hist : freq_hist; - if(afh > 1) { - attotime aper = attotime::from_double(period_adjust_base.as_double()*delta.as_double()/period.as_double()); - period += aper; - - if(period < min_period) - period = min_period; - else if(period > max_period) - period = max_period; - } - } - - return 1; -} - -bool n82077aa_device::pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit) -{ - if(write_start_time.is_never()) { - write_start_time = ctime; - write_position = 0; - } - - attotime etime = ctime + period; - if(etime > limit) - return true; - - if(write_position < ARRAY_LENGTH(write_buffer)) - write_buffer[write_position++] = ctime + period/2; - - tm = etime; - ctime = etime; - return false; -} diff --git a/src/mess/machine/n82077aa.h b/src/mess/machine/n82077aa.h deleted file mode 100644 index 0e045a3202d..00000000000 --- a/src/mess/machine/n82077aa.h +++ /dev/null @@ -1,203 +0,0 @@ -#ifndef __N82077AA_H__ -#define __N82077AA_H__ - -#include "emu.h" -#include "imagedev/floppy.h" - -#define MCFG_N82077AA_ADD(_tag, _mode) \ - MCFG_DEVICE_ADD(_tag, N82077AA, 0) \ - downcast<n82077aa_device *>(device)->set_mode(_mode); - -class n82077aa_device : public device_t { -public: - typedef delegate<void (bool state)> line_cb; - - enum { MODE_AT, MODE_PS2, MODE_M30 }; - - n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - void set_mode(int mode); - void setup_intrq_cb(line_cb cb); - void setup_drq_cb(line_cb cb); - - DECLARE_ADDRESS_MAP(amap, 8); - - DECLARE_READ8_MEMBER (sra_r); - DECLARE_READ8_MEMBER (srb_r); - DECLARE_READ8_MEMBER (dor_r); - DECLARE_WRITE8_MEMBER(dor_w); - DECLARE_READ8_MEMBER (tdr_r); - DECLARE_WRITE8_MEMBER(tdr_w); - DECLARE_READ8_MEMBER (msr_r); - DECLARE_WRITE8_MEMBER(dsr_w); - DECLARE_READ8_MEMBER (fifo_r); - DECLARE_WRITE8_MEMBER(fifo_w); - DECLARE_READ8_MEMBER (dir_r); - DECLARE_WRITE8_MEMBER(ccr_w); - - UINT8 dma_r(); - void dma_w(UINT8 data); - bool get_drq() const; - -protected: - virtual void device_start(); - virtual void device_reset(); - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); - -private: - enum { - PHASE_CMD, PHASE_EXEC, PHASE_RESULT - }; - - enum { - // General "doing nothing" state - IDLE, - - // Main states - RECALIBRATE, - SEEK, - READ_DATA, - READ_ID, - - // Sub-states - SEEK_MOVE, - SEEK_WAIT_STEP_SIGNAL_TIME, - SEEK_WAIT_STEP_SIGNAL_TIME_DONE, - SEEK_WAIT_STEP_TIME, - SEEK_WAIT_STEP_TIME_DONE, - SEEK_DONE, - - HEAD_LOAD_DONE, - - SCAN_ID, - SCAN_ID_FAILED, - - SECTOR_READ, - - // Live states - SEARCH_ADDRESS_MARK_HEADER, - READ_HEADER_BLOCK_HEADER, - READ_DATA_BLOCK_HEADER, - READ_ID_BLOCK_TO_LOCAL, - SEARCH_ADDRESS_MARK_DATA, - SEARCH_ADDRESS_MARK_DATA_FAILED, - READ_SECTOR_DATA, - READ_SECTOR_DATA_BYTE, - - }; - - struct pll_t { - attotime ctime, period, min_period, max_period, period_adjust_base, phase_adjust; - - attotime write_start_time; - attotime write_buffer[32]; - int write_position; - int freq_hist; - - void set_clock(attotime period); - void reset(attotime when); - int get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit); - bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit); - void start_writing(attotime tm); - void commit(floppy_image_device *floppy, attotime tm); - void stop_writing(floppy_image_device *floppy, attotime tm); - }; - - struct floppy_info { - emu_timer *tm; - floppy_image_device *dev; - int id; - int main_state, sub_state; - int dir, status; - UINT8 pcn; - bool irq, live, index; - }; - - struct live_info { - enum { PT_NONE, PT_CRC_1, PT_CRC_2 }; - - attotime tm; - int state, next_state; - floppy_info *fi; - UINT16 shift_reg; - UINT16 crc; - int bit_counter, byte_counter, previous_type; - bool data_separator_phase, data_bit_context; - UINT8 data_reg; - UINT8 idbuf[6]; - pll_t pll; - }; - - static int rates[4]; - - int mode; - int main_phase; - int counter; - - live_info cur_live, checkpoint_live; - line_cb intrq_cb, drq_cb; - bool cur_irq, data_irq, drq; - floppy_info flopi[4]; - - int fifo_pos, fifo_expected, command_pos, result_pos; - bool fifo_write; - UINT8 dor, dsr, msr, fifo[16], command[16], result[16]; - UINT8 fifocfg; - UINT16 spec; - int sector_size; - - static astring tts(attotime t); - astring ttsn(); - - enum { - C_CONFIGURE, - C_PERPENDICULAR, - C_READ_DATA, - C_READ_ID, - C_RECALIBRATE, - C_SEEK, - C_SENSE_INTERRUPT_STATUS, - C_SPECIFY, - - C_INVALID, - C_INCOMPLETE, - }; - - void delay_cycles(emu_timer *tm, int cycles); - void check_irq(); - void fifo_expect(int size, bool write); - void fifo_push(UINT8 data); - void set_drq(bool state); - - int check_command(); - void start_command(int cmd); - void command_end(floppy_info &fi, bool data_completion, int status); - - void recalibrate_start(floppy_info &fi); - void seek_start(floppy_info &fi); - void seek_continue(floppy_info &fi); - - void read_data_start(floppy_info &fi); - void read_data_continue(floppy_info &fi); - - void read_id_start(floppy_info &fi); - void read_id_continue(floppy_info &fi); - - void general_continue(floppy_info &fi); - void index_callback(floppy_image_device *floppy, int state); - bool sector_matches() const; - - void live_start(floppy_info &fi, int live_state); - void live_abort(); - void checkpoint(); - void rollback(); - void live_delay(int state); - void live_sync(); - void live_run(attotime limit = attotime::never); - - bool read_one_bit(attotime limit); - bool write_one_bit(attotime limit); -}; - -extern const device_type N82077AA; - -#endif diff --git a/src/mess/machine/pc.c b/src/mess/machine/pc.c index d24e2cac56b..ef62505961e 100644 --- a/src/mess/machine/pc.c +++ b/src/mess/machine/pc.c @@ -202,7 +202,7 @@ WRITE8_MEMBER(pc_state::pc_dma_write_byte) READ8_MEMBER(pc_state::pc_dma8237_fdc_dack_r) { - return pc_fdc_dack_r(machine(), space); + return machine().device<pc_fdc_interface>("fdc")->dma_r(); } @@ -214,7 +214,7 @@ READ8_MEMBER(pc_state::pc_dma8237_hdc_dack_r) WRITE8_MEMBER(pc_state::pc_dma8237_fdc_dack_w) { - pc_fdc_dack_w( machine(), space, data ); + machine().device<pc_fdc_interface>("fdc")->dma_w(data); } @@ -232,7 +232,7 @@ WRITE8_MEMBER(pc_state::pc_dma8237_0_dack_w) WRITE_LINE_MEMBER(pc_state::pc_dma8237_out_eop) { - pc_fdc_set_tc_state( machine(), state == ASSERT_LINE ? 0 : 1 ); + machine().device<pc_fdc_interface>("fdc")->tc_w(state == ASSERT_LINE); } static void set_dma_channel(running_machine &machine, int channel, int state) @@ -1136,44 +1136,19 @@ I8255_INTERFACE( mc1502_ppi8255_interface_2 ) * **********************************************************/ -static void pc_fdc_interrupt(running_machine &machine, int state) +void pc_state::fdc_interrupt(bool state) { - pc_state *st = machine.driver_data<pc_state>(); - if (st->m_pic8259) + if (m_pic8259) { - pic8259_ir6_w(st->m_pic8259, state); + pic8259_ir6_w(m_pic8259, state); } } -static void pc_fdc_dma_drq(running_machine &machine, int state) +void pc_state::fdc_dma_drq(bool state) { - pc_state *st = machine.driver_data<pc_state>(); - i8237_dreq2_w( st->m_dma8237, state); + i8237_dreq2_w( m_dma8237, state); } -static device_t * pc_get_device(running_machine &machine ) -{ - return machine.device("upd765"); -} - -static const struct pc_fdc_interface fdc_interface_nc = -{ - pc_fdc_interrupt, - pc_fdc_dma_drq, - NULL, - pc_get_device -}; - - -static const struct pc_fdc_interface pcjr_fdc_interface_nc = -{ - pc_fdc_interrupt, - NULL, - NULL, - pc_get_device -}; - - static void pc_set_irq_line(running_machine &machine,int irq, int state) { pc_state *st = machine.driver_data<pc_state>(); @@ -1396,7 +1371,10 @@ MACHINE_START_MEMBER(pc_state,pc) m_pic8259 = machine().device("pic8259"); m_dma8237 = machine().device("dma8237"); m_pit8253 = machine().device("pit8253"); - pc_fdc_init( machine(), &fdc_interface_nc ); + + pc_fdc_interface *fdc = machine().device<pc_fdc_interface>("fdc"); + fdc->setup_intrq_cb(pc_fdc_interface::line_cb(FUNC(pc_state::fdc_interrupt), this)); + fdc->setup_drq_cb(pc_fdc_interface::line_cb(FUNC(pc_state::fdc_dma_drq), this)); } @@ -1450,8 +1428,8 @@ MACHINE_START_MEMBER(pc_state,mc1502) MACHINE_START_MEMBER(pc_state,pcjr) { - pc_fdc_init( machine(), &pcjr_fdc_interface_nc ); - pcjr_keyb.keyb_signal_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pc_state::pcjr_keyb_signal_callback),this)); + pc_fdc_interface *fdc = machine().device<pc_fdc_interface>("fdc"); + fdc->setup_intrq_cb(pc_fdc_interface::line_cb(FUNC(pc_state::fdc_interrupt), this)); pc_int_delay_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(pc_state::pcjr_delayed_pic8259_irq),this)); m_maincpu = machine().device<cpu_device>("maincpu" ); m_maincpu->set_irq_acknowledge_callback(pc_irq_callback); diff --git a/src/mess/machine/pc_fdc.c b/src/mess/machine/pc_fdc.c index 9a6a33cbbde..3c7570ed9be 100644 --- a/src/mess/machine/pc_fdc.c +++ b/src/mess/machine/pc_fdc.c @@ -13,7 +13,198 @@ #include "emu.h" #include "machine/pc_fdc.h" -#include "machine/upd765.h" + +const device_type PC_FDC_XT = &device_creator<pc_fdc_xt_device>; +const device_type PC_FDC_AT = &device_creator<pc_fdc_at_device>; +const device_type PC_FDC_JR = &device_creator<pc_fdc_jr_device>; + +static MACHINE_CONFIG_FRAGMENT( cfg ) + MCFG_UPD765A_ADD("upd765", false, false) +MACHINE_CONFIG_END + +DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_family_device) +ADDRESS_MAP_END + +// The schematics show address decoding is minimal +DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_xt_device) + AM_RANGE(0x0, 0x0) AM_DEVREAD("upd765", upd765a_device, msr_r) AM_WRITE(dor_w) + AM_RANGE(0x1, 0x1) AM_DEVREAD("upd765", upd765a_device, fifo_r) AM_WRITE(dor_fifo_w) + AM_RANGE(0x2, 0x2) AM_WRITE(dor_w) + AM_RANGE(0x3, 0x3) AM_WRITE(dor_w) + AM_RANGE(0x4, 0x5) AM_DEVICE("upd765", upd765a_device, map) +ADDRESS_MAP_END + + +// Decoding is through a PAL, so presumably complete +DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_at_device) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x4, 0x5) AM_DEVICE("upd765", upd765a_device, map) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END + + + +pc_fdc_family_device::pc_fdc_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : pc_fdc_interface(mconfig, type, name, tag, owner, clock), fdc(*this, "upd765") +{ +} + +void pc_fdc_family_device::setup_intrq_cb(line_cb cb) +{ + intrq_cb = cb; +} + +void pc_fdc_family_device::setup_drq_cb(line_cb cb) +{ + drq_cb = cb; +} + +void pc_fdc_family_device::tc_w(bool state) +{ + fdc->tc_w(state); +} + +UINT8 pc_fdc_family_device::dma_r() +{ + return fdc->dma_r(); +} + +void pc_fdc_family_device::dma_w(UINT8 data) +{ + fdc->dma_w(data); +} + +machine_config_constructor pc_fdc_family_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME(cfg); +} + +void pc_fdc_family_device::device_start() +{ + fdc->setup_intrq_cb(upd765a_device::line_cb(FUNC(pc_fdc_family_device::irq_w), this)); + fdc->setup_drq_cb(upd765a_device::line_cb(FUNC(pc_fdc_family_device::drq_w), this)); + + for(int i=0; i<4; i++) { + char name[2] = {'0'+i, 0}; + floppy_connector *conn = subdevice<floppy_connector>(name); + floppy[i] = conn ? conn->get_device() : NULL; + } + + irq = drq = false; + fdc_irq = fdc_drq = false; + dor = 0x00; +} + +void pc_fdc_family_device::device_reset() +{ +} + +// Bits 0-1 select one of the 4 drives, but only if the associated +// motor bit is on + +// Bit 2 is tied to the upd765 reset line + +// Bit 3 enables the irq and drq lines + +// Bit 4-7 control the drive motors + +WRITE8_MEMBER( pc_fdc_family_device::dor_w ) +{ + logerror("%s: dor = %02x\n", tag(), data); + UINT8 pdor = dor; + dor = data; + + for(int i=0; i<4; i++) + if(floppy[i]) + floppy[i]->mon_w(!(dor & (0x10 << i))); + + int fid = dor & 3; + if(dor & (0x10 << fid)) + fdc->set_floppy(floppy[fid]); + else + fdc->set_floppy(NULL); + + check_irq(); + check_drq(); + if((pdor^dor) & 4) + fdc->reset(); +} + +READ8_MEMBER( pc_fdc_family_device::dor_r ) +{ + return dor; +} + +READ8_MEMBER( pc_fdc_family_device::dir_r ) +{ + return do_dir_r(); +} + +WRITE8_MEMBER( pc_fdc_family_device::ccr_w ) +{ + static const int rates[4] = { 500000, 300000, 250000, 1000000 }; + logerror("%s: ccr = %02x\n", tag(), data); + fdc->set_rate(rates[data & 3]); +} + +UINT8 pc_fdc_family_device::do_dir_r() +{ + if(floppy[dor & 3]) + return floppy[dor & 3]->dskchg_r() ? 0x00 : 0x80; + return 0x00; +} + +WRITE8_MEMBER( pc_fdc_xt_device::dor_fifo_w) +{ + fdc->fifo_w(space, 0, data, mem_mask); + dor_w(space, 0, data, mem_mask); +} + +void pc_fdc_family_device::irq_w(bool state) +{ + fdc_irq = state; + check_irq(); +} + +void pc_fdc_family_device::drq_w(bool state) +{ + fdc_drq = state; + check_drq(); +} + +void pc_fdc_family_device::check_irq() +{ + bool pirq = irq; + irq = fdc_irq && (dor & 4) && (dor & 8); + if(irq != pirq && !intrq_cb.isnull()) { + logerror("%s: pc_irq = %d\n", tag(), irq); + intrq_cb(irq); + } +} + +void pc_fdc_family_device::check_drq() +{ + bool pdrq = drq; + drq = fdc_drq && (dor & 4) && (dor & 8); + if(drq != pdrq && !drq_cb.isnull()) + drq_cb(drq); +} + +pc_fdc_xt_device::pc_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : pc_fdc_family_device(mconfig, PC_FDC_XT, "PC FDC XT", tag, owner, clock) +{ + m_shortname = "pc_fdc_xt"; +} + +pc_fdc_at_device::pc_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : pc_fdc_family_device(mconfig, PC_FDC_AT, "PC FDC AT", tag, owner, clock) +{ + m_shortname = "pc_fdc_at"; +} + +pc_fdc_jr_device::pc_fdc_jr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : pc_fdc_family_device(mconfig, PC_FDC_JR, "PC FDC JR", tag, owner, clock) +{ + m_shortname = "pc_fdc_jr"; +} + +#if 0 /* if not 1, DACK and TC inputs to FDC are disabled, and DRQ and IRQ are held @@ -579,3 +770,4 @@ WRITE8_HANDLER ( pcjr_fdc_w ) } } +#endif diff --git a/src/mess/machine/pc_fdc.h b/src/mess/machine/pc_fdc.h index a5b32975a9a..e812b5ac6a2 100644 --- a/src/mess/machine/pc_fdc.h +++ b/src/mess/machine/pc_fdc.h @@ -8,8 +8,84 @@ #define PC_FDC_H #include "emu.h" -#include "machine/upd765.h" +#include "imagedev/floppy.h" +#include "upd765.h" +#define MCFG_PC_FDC_XT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PC_FDC_XT, 0) + +#define MCFG_PC_FDC_AT_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PC_FDC_AT, 0) + +#define MCFG_PC_FDC_JR_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PC_FDC_JR, 0) + + +class pc_fdc_family_device : public pc_fdc_interface { +public: + pc_fdc_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); + + required_device<upd765a_device> fdc; + + virtual void setup_intrq_cb(line_cb cb); + virtual void setup_drq_cb(line_cb cb); + + virtual DECLARE_ADDRESS_MAP(map, 8); + + virtual void tc_w(bool state); + virtual UINT8 dma_r(); + virtual void dma_w(UINT8 data); + virtual UINT8 do_dir_r(); + + READ8_MEMBER(dor_r); + WRITE8_MEMBER(dor_w); + READ8_MEMBER(dir_r); + WRITE8_MEMBER(ccr_w); + +protected: + virtual void device_start(); + virtual void device_reset(); + virtual machine_config_constructor device_mconfig_additions() const; + + line_cb intrq_cb, drq_cb; + bool irq, drq, fdc_drq, fdc_irq; + UINT8 dor; + + floppy_image_device *floppy[4]; + + void irq_w(bool state); + void drq_w(bool state); + void check_irq(); + void check_drq(); +}; + +class pc_fdc_xt_device : public pc_fdc_family_device { +public: + pc_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); + WRITE8_MEMBER(dor_fifo_w); +}; + +class pc_fdc_at_device : public pc_fdc_family_device { +public: + pc_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual DECLARE_ADDRESS_MAP(map, 8); +}; + +class pc_fdc_jr_device : public pc_fdc_family_device { +public: + pc_fdc_jr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type PC_FDC_XT; +extern const device_type PC_FDC_AT; +extern const device_type PC_FDC_JR; + + +#if 0 /* interface has been seperated, so that it can be used in the super i/o chip */ #define PC_FDC_STATUS_REGISTER_A 0 @@ -47,6 +123,7 @@ DECLARE_READ8_HANDLER(pc_fdc_r); DECLARE_WRITE8_HANDLER(pc_fdc_w); DECLARE_WRITE8_HANDLER ( pcjr_fdc_w ); +#endif #endif /* PC_FDC_H */ diff --git a/src/mess/machine/pf10.c b/src/mess/machine/pf10.c index 532b22bb444..592466b7ad1 100644 --- a/src/mess/machine/pf10.c +++ b/src/mess/machine/pf10.c @@ -57,21 +57,12 @@ ADDRESS_MAP_END MACHINE CONFIG *****************************************************************************/ -static const upd765_interface pf10_upd765a_intf = -{ - DEVCB_NULL, /* interrupt line */ - DEVCB_NULL, - NULL, - UPD765_RDY_PIN_NOT_CONNECTED, /* ??? */ - {NULL, NULL, NULL, NULL} -}; - static MACHINE_CONFIG_FRAGMENT( pf10 ) MCFG_CPU_ADD("pf10", M6803, XTAL_2_4576MHz / 4 /* ??? */) /* HD63A03 */ MCFG_CPU_PROGRAM_MAP(pf10_mem) MCFG_CPU_IO_MAP(pf10_io) - MCFG_UPD765A_ADD("upd765a", pf10_upd765a_intf) + MCFG_UPD765A_ADD("upd765a", false, true) MACHINE_CONFIG_END diff --git a/src/mess/machine/tf20.c b/src/mess/machine/tf20.c index bec671478f1..e01cddfa489 100644 --- a/src/mess/machine/tf20.c +++ b/src/mess/machine/tf20.c @@ -16,7 +16,7 @@ #include "machine/upd7201.h" #include "machine/upd765.h" #include "imagedev/flopdrv.h" - +#include "formats/mfi_dsk.h" /*************************************************************************** CONSTANTS @@ -32,11 +32,16 @@ struct tf20_state { + device_t *cpu; ram_device *ram; - device_t *upd765a; + upd765a_device *upd765a; upd7201_device *upd7201; - device_t *floppy_0; - device_t *floppy_1; + floppy_image_device *floppy_0; + floppy_image_device *floppy_1; + + void fdc_int(bool state) { + cpu->execute().set_input_line(INPUT_LINE_IRQ0, state ? ASSERT_LINE : CLEAR_LINE); + } }; @@ -89,15 +94,16 @@ static READ8_HANDLER( tf20_dip_r ) static TIMER_CALLBACK( tf20_upd765_tc_reset ) { - upd765_tc_w((device_t *)ptr, CLEAR_LINE); + static_cast<upd765a_device *>(ptr)->tc_w(false); } static READ8_DEVICE_HANDLER( tf20_upd765_tc_r ) { - logerror("%s: tf20_upd765_tc_r\n", space.machine().describe_context()); + tf20_state *tf20 = get_safe_token(device->owner()); + logerror("%s: tf20_upd765_tc_r\n", device->machine().describe_context()); /* toggle tc on read */ - upd765_tc_w(device, ASSERT_LINE); + tf20->upd765a->tc_w(true); space.machine().scheduler().timer_set(attotime::zero, FUNC(tf20_upd765_tc_reset), 0, device); return 0xff; @@ -109,8 +115,8 @@ static WRITE8_HANDLER( tf20_fdc_control_w ) logerror("%s: tf20_fdc_control_w %02x\n", space.machine().describe_context(), data); /* bit 0, motor on signal */ - floppy_mon_w(tf20->floppy_0, !BIT(data, 0)); - floppy_mon_w(tf20->floppy_1, !BIT(data, 0)); + tf20->floppy_0->mon_w(!BIT(data, 0)); + tf20->floppy_1->mon_w(!BIT(data, 0)); } static IRQ_CALLBACK( tf20_irq_ack ) @@ -210,8 +216,7 @@ static ADDRESS_MAP_START( tf20_io, AS_IO, 8, tf20_device ) AM_RANGE(0xf6, 0xf6) AM_READ_LEGACY(tf20_rom_disable) AM_RANGE(0xf7, 0xf7) AM_READ_LEGACY(tf20_dip_r) AM_RANGE(0xf8, 0xf8) AM_DEVREAD_LEGACY("5a", tf20_upd765_tc_r) AM_WRITE_LEGACY(tf20_fdc_control_w) - AM_RANGE(0xfa, 0xfa) AM_DEVREAD_LEGACY("5a", upd765_status_r) - AM_RANGE(0xfb, 0xfb) AM_DEVREADWRITE_LEGACY("5a", upd765_data_r, upd765_data_w) + AM_RANGE(0xfa, 0xfb) AM_DEVICE("5a", upd765a_device, map) ADDRESS_MAP_END @@ -266,28 +271,15 @@ static UPD7201_INTERFACE( tf20_upd7201_intf ) } }; -static const upd765_interface tf20_upd765a_intf = -{ - DEVCB_CPU_INPUT_LINE("tf20", INPUT_LINE_IRQ0), - DEVCB_NULL, - NULL, - UPD765_RDY_PIN_NOT_CONNECTED, - {FLOPPY_0, FLOPPY_1, NULL, NULL} -}; - -static const floppy_interface tf20_floppy_interface = -{ - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - DEVCB_NULL, - FLOPPY_STANDARD_5_25_DSDD_40, - LEGACY_FLOPPY_OPTIONS_NAME(default), - NULL, +static const floppy_format_type tf20_floppy_formats[] = { + FLOPPY_MFI_FORMAT, NULL }; +static SLOT_INTERFACE_START( tf20_floppies ) + SLOT_INTERFACE( "525dd", FLOPPY_525_DD ) +SLOT_INTERFACE_END + static MACHINE_CONFIG_FRAGMENT( tf20 ) MCFG_CPU_ADD("tf20", Z80, XTAL_CR1 / 2) /* uPD780C */ MCFG_CPU_PROGRAM_MAP(tf20_mem) @@ -298,14 +290,15 @@ static MACHINE_CONFIG_FRAGMENT( tf20 ) MCFG_RAM_DEFAULT_SIZE("64k") /* upd765a floppy controller */ - MCFG_UPD765A_ADD("5a", tf20_upd765a_intf) + MCFG_UPD765A_ADD("5a", false, true) /* upd7201 serial interface */ MCFG_UPD7201_ADD("3a", XTAL_CR1 / 2, tf20_upd7201_intf) MCFG_TIMER_ADD_PERIODIC("serial_timer", serial_clock, attotime::from_hz(XTAL_CR2 / 128)) /* 2 floppy drives */ - MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(tf20_floppy_interface) + MCFG_FLOPPY_DRIVE_ADD("5a:0", tf20_floppies, "525dd", 0, tf20_floppy_formats) + MCFG_FLOPPY_DRIVE_ADD("5a:1", tf20_floppies, "525dd", 0, tf20_floppy_formats) MACHINE_CONFIG_END @@ -326,10 +319,10 @@ ROM_END static DEVICE_START( tf20 ) { tf20_state *tf20 = get_safe_token(device); - device_t *cpu = device->subdevice("tf20"); - address_space &prg = cpu->memory().space(AS_PROGRAM); + tf20->cpu = device->subdevice("tf20"); + address_space &prg = tf20->cpu->memory().space(AS_PROGRAM); - cpu->execute().set_irq_acknowledge_callback(tf20_irq_ack); + tf20->cpu->execute().set_irq_acknowledge_callback(tf20_irq_ack); /* ram device */ tf20->ram = device->subdevice<ram_device>("ram"); @@ -339,10 +332,13 @@ static DEVICE_START( tf20 ) throw device_missing_dependencies(); /* locate child devices */ - tf20->upd765a = device->subdevice("5a"); + tf20->upd765a = device->subdevice<upd765a_device>("5a"); tf20->upd7201 = downcast<upd7201_device *>(device->subdevice("3a")); - tf20->floppy_0 = device->subdevice(FLOPPY_0); - tf20->floppy_1 = device->subdevice(FLOPPY_1); + tf20->floppy_0 = device->subdevice<floppy_connector>("5a:0")->get_device(); + tf20->floppy_1 = device->subdevice<floppy_connector>("5a:1")->get_device(); + + /* hookup the irq */ + tf20->upd765a->setup_intrq_cb(upd765a_device::line_cb(FUNC(tf20_state::fdc_int), tf20)); /* enable second half of ram */ prg.install_ram(0x8000, 0xffff, tf20->ram->pointer() + 0x8000); diff --git a/src/mess/machine/upd765.c b/src/mess/machine/upd765.c index bb44c341107..29d476b329f 100644 --- a/src/mess/machine/upd765.c +++ b/src/mess/machine/upd765.c @@ -1,2570 +1,2139 @@ -/*************************************************************************** +#include "debugger.h" - machine/upd765.c +#include "upd765.h" - Functions to emulate a UPD765/Intel 8272 compatible floppy disk controller - - Code by Kevin Thacker. - - TODO: - - - overrun condition - - Scan Commands - - crc error in id field and crc error in data field errors - - disc not present, and no sectors on track for data, deleted data, write, write deleted, - read a track etc - - end of cylinder condition - almost working, needs fixing with - PCW and PC drivers - - resolve "ready" state stuff (ready state when reset for PC, ready state change while processing command AND - while idle) - - Changes: - 091006 (Mariusz Wojcieszek, changes needed by QX-10): - - allowed "Sense Interrupt Status" command when Seek is active - - DIO bit in status register (0x40) is cleared when "Read Data" command is executed, - it is later set during result phase. - -***************************************************************************/ - -#include "emu.h" -#include "machine/upd765.h" - - -enum UPD765_PHASE -{ - UPD765_COMMAND_PHASE_FIRST_BYTE, - UPD765_COMMAND_PHASE_BYTES, - UPD765_RESULT_PHASE, - UPD765_EXECUTION_PHASE_READ, - UPD765_EXECUTION_PHASE_WRITE -}; - -/* supported versions */ -enum UPD765_VERSION -{ - TYPE_UPD765A = 0, - TYPE_UPD765B = 1, - TYPE_SMC37C78 = 2, - TYPE_UPD72065 = 3 -}; - - -/* uncomment the following line for verbose information */ -#define LOG_VERBOSE 0 -#define LOG_COMMAND 0 -#define LOG_EXTRA 0 -#define LOG_INTERRUPT 0 - -/* uncomment this to not allow end of cylinder "error" */ -#define NO_END_OF_CYLINDER +const device_type UPD765A = &device_creator<upd765a_device>; +const device_type UPD765B = &device_creator<upd765b_device>; +const device_type I8272A = &device_creator<i8272a_device>; +const device_type UPD72065 = &device_creator<upd72065_device>; +const device_type SMC37C78 = &device_creator<smc37c78_device>; +const device_type N82077AA = &device_creator<n82077aa_device>; +const device_type PC_FDC_SUPERIO = &device_creator<pc_fdc_superio_device>; +DEVICE_ADDRESS_MAP_START(map, 8, upd765a_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END +DEVICE_ADDRESS_MAP_START(map, 8, upd765b_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END -/* state of upd765 Interrupt (INT) output */ -#define UPD765_INT 0x02 -/* data rate for floppy discs (MFM data) */ -#define UPD765_DATA_RATE 32 -/* state of upd765 terminal count input*/ -#define UPD765_TC 0x04 +DEVICE_ADDRESS_MAP_START(map, 8, i8272a_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END -#define UPD765_DMA_MODE 0x08 +DEVICE_ADDRESS_MAP_START(map, 8, upd72065_device) + AM_RANGE(0x0, 0x0) AM_READ(msr_r) + AM_RANGE(0x1, 0x1) AM_READWRITE(fifo_r, fifo_w) +ADDRESS_MAP_END -#define UPD765_SEEK_OPERATION_IS_RECALIBRATE 0x01 +DEVICE_ADDRESS_MAP_START(map, 8, smc37c78_device) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END -#define UPD765_SEEK_ACTIVE 0x010 -/* state of upd765 DMA DRQ output */ -#define UPD765_DMA_DRQ 0x020 -/* state of upd765 FDD READY input */ -#define UPD765_FDD_READY 0x040 +DEVICE_ADDRESS_MAP_START(map, 8, n82077aa_device) + AM_RANGE(0x0, 0x0) AM_READ(sra_r) + AM_RANGE(0x1, 0x1) AM_READ(srb_r) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END -#define UPD765_MF 0x40 -#define UPD765_MT 0x80 +DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_superio_device) + AM_RANGE(0x0, 0x0) AM_READ(sra_r) + AM_RANGE(0x1, 0x1) AM_READ(srb_r) + AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(tdr_r, tdr_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(msr_r, dsr_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w) +ADDRESS_MAP_END -#define UPD765_RESET 0x080 -#define UPD765_BAD_MEDIA 0x100 +int upd765_family_device::rates[4] = { 500000, 300000, 250000, 1000000 }; -struct upd765_t +upd765_family_device::upd765_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : pc_fdc_interface(mconfig, type, name, tag, owner, clock) { - devcb_resolved_write_line out_int_func; - devcb_resolved_write_line out_drq_func; - - unsigned long sector_counter; - /* version of fdc to emulate */ - UPD765_VERSION version; - - /* main status register */ - unsigned char FDC_main; - /* data register */ - unsigned char upd765_data_reg; - - unsigned char c,h,r,n; - - int sector_id; - - int data_type; - - char format_data[4]; - - UPD765_PHASE upd765_phase; - unsigned int upd765_command_bytes[16]; - unsigned int upd765_result_bytes[16]; - unsigned int upd765_transfer_bytes_remaining; - unsigned int upd765_transfer_bytes_count; - unsigned int upd765_status[4]; - /* present cylinder number per drive */ - unsigned int pcn[4]; - - /* drive being accessed. drive outputs from fdc */ - unsigned int drive; - /* side being accessed: side output from fdc */ - unsigned int side; - - - /* step rate time in us */ - unsigned long srt_in_ms; - - unsigned int ncn; - -// unsigned int upd765_id_index; - char *execution_phase_data; - unsigned int upd765_flags; + ready_polled = true; + ready_connected = true; + select_connected = true; + external_ready = true; + dor_reset = 0x00; +} -// unsigned char specify[2]; -// unsigned char perpendicular_mode[1]; +void upd765_family_device::set_ready_line_connected(bool _ready) +{ + ready_connected = _ready; +} - int command; +void upd765_family_device::set_select_lines_connected(bool _select) +{ + select_connected = _select; +} - UINT8 ready_changed; +void upd765_family_device::set_mode(int _mode) +{ + // TODO +} - emu_timer *seek_timer; - emu_timer *timer; - int timer_type; +void upd765_family_device::setup_intrq_cb(line_cb cb) +{ + intrq_cb = cb; +} - emu_timer *command_timer; +void upd765_family_device::setup_drq_cb(line_cb cb) +{ + drq_cb = cb; +} - char *data_buffer; - const upd765_interface *intf; +void upd765_family_device::device_start() +{ + for(int i=0; i != 4; i++) { + char name[2]; + flopi[i].tm = timer_alloc(i); + flopi[i].id = i; + if(select_connected) { + name[0] = '0'+i; + name[1] = 0; + floppy_connector *con = subdevice<floppy_connector>(name); + if(con) { + flopi[i].dev = con->get_device(); + flopi[i].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(upd765_family_device::index_callback), this)); + } else + flopi[i].dev = NULL; + } else + flopi[i].dev = NULL; + } + cur_rate = 250000; + tc = false; - bool pool; -}; + // reset at upper levels may cause a write to tc ending up with + // live_sync, which will crash if the live structure isn't + // initialized enough -//static void upd765_setup_data_request(unsigned char Data); -static void upd765_setup_command(device_t *device); -static TIMER_CALLBACK(upd765_continue_command); -static int upd765_sector_count_complete(device_t *device); -static void upd765_increment_sector(device_t *device); -static void upd765_update_state(device_t *device); -static void upd765_set_dma_drq(device_t *device,int state); -static void upd765_set_int(device_t *device,int state); + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.fi = NULL; -static const INT8 upd765_cmd_size[32] = -{ - 1,1,9,3,2,9,9,2,1,9,2,1,9,6,1,3, - 1,9,1,1,1,1,9,1,1,9,1,1,1,9,1,1 -}; + if(ready_polled) { + poll_timer = timer_alloc(TIMER_DRIVE_READY_POLLING); + poll_timer->adjust(attotime::from_usec(1024), 0, attotime::from_usec(1024)); + } else + poll_timer = NULL; -INLINE upd765_t *get_safe_token(device_t *device) -{ - assert(device != NULL); - assert(device->type() == UPD765A || device->type() == UPD765B || - device->type() == SMC37C78 || device->type() == UPD72065); - - return (upd765_t *)downcast<upd765a_device *>(device)->token(); + cur_irq = false; } -static device_t *current_image(device_t *device) +void upd765_family_device::device_reset() { - device_t *image = NULL; - upd765_t *fdc = get_safe_token(device); - - if (!fdc->intf->get_image) - { - if (fdc->intf->floppy_drive_tags[fdc->drive] != NULL) - { - if (device->owner() != NULL) - image = device->owner()->subdevice(fdc->intf->floppy_drive_tags[fdc->drive]); - else - image = device->machine().device(fdc->intf->floppy_drive_tags[fdc->drive]); - } + main_phase = PHASE_CMD; + for(int i=0; i<4; i++) { + flopi[i].main_state = IDLE; + flopi[i].sub_state = IDLE; + flopi[i].irq_seek = false; + flopi[i].live = false; + flopi[i].ready = !ready_polled; + flopi[i].irq_polled = false; } - else - { - image = fdc->intf->get_image(device, fdc->drive); - } - return image; + data_irq = false; + internal_drq = false; + fifo_pos = 0; + command_pos = 0; + result_pos = 0; + fifocfg = FIF_DIS; + cur_live.fi = 0; + drq = false; + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; + cur_live.fi = NULL; + tc_done = false; + st0 = st1 = st2 = st3 = 0x00; + dor = dor_reset; + + check_irq(); + if(ready_polled) + poll_timer->adjust(attotime::from_usec(1024), 0, attotime::from_usec(1024)); } -static void upd765_setup_drive_and_side(device_t *device) +void upd765_family_device::tc_w(bool _tc) { - upd765_t *fdc = get_safe_token(device); - /* drive index upd765 sees */ - fdc->drive = fdc->upd765_command_bytes[1] & 0x03; - /* side index upd765 sees */ - fdc->side = (fdc->upd765_command_bytes[1]>>2) & 0x01; + logerror("%s: tc=%d\n", tag(), _tc); + if(tc != _tc && _tc) { + live_sync(); + tc_done = true; + tc = _tc; + if(cur_live.fi) + general_continue(*cur_live.fi); + } else + tc = _tc; } - -/* setup status register 0 based on data in status register 1 and 2 */ -static void upd765_setup_st0(device_t *device) +void upd765_family_device::ready_w(bool _ready) { - upd765_t *fdc = get_safe_token(device); - /* clear completition status bits, drive bits and side bits */ - fdc->upd765_status[0] &= ~((1<<7) | (1<<6) | (1<<2) | (1<<1) | (1<<0)); - /* fill in drive */ - fdc->upd765_status[0] |= fdc->drive | (fdc->side<<2); - - /* fill in completion status bits based on bits in st0, st1, st2 */ - /* no error bits set */ - if ((fdc->upd765_status[1] | fdc->upd765_status[2])==0) - { - return; - } - - fdc->upd765_status[0] |= 0x040; + external_ready = _ready; } - -static int upd765_n_to_bytes(int n) +bool upd765_family_device::get_ready(int fid) { - /* 0-> 128 bytes, 1->256 bytes, 2->512 bytes etc */ - /* data_size = ((1<<(N+7)) */ - return 1<<(n+7); + if(ready_connected) + return flopi[fid].dev ? flopi[fid].dev->ready_r() : false; + return external_ready; } -static void upd765_set_data_request(device_t *device) +void upd765_family_device::set_floppy(floppy_image_device *flop) { - upd765_t *fdc = get_safe_token(device); - fdc->FDC_main |= 0x080; + for(int fid=0; fid<4; fid++) { + if(flopi[fid].dev) + flopi[fid].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); + flopi[fid].dev = flop; + } + if(flop) + flop->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(upd765_family_device::index_callback), this)); +} + +READ8_MEMBER(upd765_family_device::sra_r) +{ + UINT8 sra = 0; + int fid = dor & 3; + floppy_info &fi = flopi[fid]; + if(fi.dir) + sra |= 0x01; + if(fi.index) + sra |= 0x04; + if(cur_rate >= 500000) + sra |= 0x08; + if(fi.dev && fi.dev->trk00_r()) + sra |= 0x10; + if(fi.main_state == SEEK_WAIT_STEP_SIGNAL_TIME) + sra |= 0x20; + sra |= 0x40; + if(cur_irq) + sra |= 0x80; + if(mode == MODE_M30) + sra ^= 0x1f; + return sra; +} + +READ8_MEMBER(upd765_family_device::srb_r) +{ + return 0; } -static void upd765_clear_data_request(device_t *device) +READ8_MEMBER(upd765_family_device::dor_r) { - upd765_t *fdc = get_safe_token(device); - fdc->FDC_main &= ~0x080; + return dor; } -static int upd765_get_rdy(device_t *device) +WRITE8_MEMBER(upd765_family_device::dor_w) { - upd765_t *fdc = get_safe_token(device); + logerror("%s: dor = %02x\n", tag(), data); + UINT8 diff = dor ^ data; + dor = data; + if(diff & 4) { + UINT8 tmp = dor_reset; + dor_reset = dor; + device_reset(); + dor_reset = tmp; + } - if (fdc->intf->rdy_pin == UPD765_RDY_PIN_CONNECTED) - { - device_t *img = current_image(device); - if (img!=NULL) { - return floppy_drive_get_flag_state(img, FLOPPY_DRIVE_READY); - } else { - return 0; - } + for(int i=0; i<4; i++) { + floppy_info &fi = flopi[i]; + if(fi.dev) + fi.dev->mon_w(!(dor & (0x10 << i))); } - else - return 1; + check_irq(); } -static void upd765_seek_complete(device_t *device) +READ8_MEMBER(upd765_family_device::tdr_r) { - /* tested on Amstrad CPC */ - - /* if a seek is done without drive connected: */ - /* abnormal termination of command, - seek complete, - not ready - */ - - /* if a seek is done with drive connected, but disc missing: */ - /* abnormal termination of command, - seek complete, - not ready */ - - /* if a seek is done with drive connected and disc in drive */ - /* seek complete */ - - - /* On the PC however, it appears that recalibrates and seeks can be performed without - a disc in the drive. */ - - /* Therefore, the above output is dependant on the state of the drive */ - - /* In the Amstrad CPC, the drive select is provided by the UPD765. A single port is also - assigned for setting the drive motor state. The motor state controls the motor of the selected - drive */ - - /* On the PC the drive can be selected with the DIGITAL OUTPUT REGISTER, and the motor of each - of the 4 possible drives is also settable using the same register */ - - /* Assumption for PC: (NOT TESTED - NEEDS VERIFICATION) */ - - /* If a seek is done without drive connected: */ - /* abnormal termination of command, - seek complete, - fault - */ - - /* if a seek is done with drive connected, but disc missing: */ - /* seek complete */ - - /* if a seek is done with drive connected and disc in drive: */ - /* seek complete */ - - /* On Amstrad CPC: - If drive not connected, or drive connected but disc not in drive, not ready! - If drive connected and drive motor on, ready! - On PC: - Drive is always ready! - - In 37c78 docs, the ready bits of the upd765 are marked as unused. - This indicates it is always ready!!!!! - */ - - device_t *img = current_image(device); - upd765_t *fdc = get_safe_token(device); + return 0; +} - fdc->pcn[fdc->drive] = fdc->ncn; +WRITE8_MEMBER(upd765_family_device::tdr_w) +{ +} - fdc->upd765_status[0] = 0x20; +READ8_MEMBER(upd765_family_device::msr_r) +{ + UINT32 msr = 0; + switch(main_phase) { + case PHASE_CMD: + msr |= MSR_RQM; + if(command_pos) + msr |= MSR_CB; + break; + case PHASE_EXEC: + msr |= MSR_CB; + if(spec & SPEC_ND) + msr |= MSR_EXM; + if(internal_drq) + msr |= MSR_RQM; + break; - /* drive ready? */ - if (img != NULL && upd765_get_rdy(device)) - { - /* recalibrate? */ - if (fdc->upd765_flags & UPD765_SEEK_OPERATION_IS_RECALIBRATE) - { - /* not at track 0? */ - if (fdc->pcn[fdc->drive] != 0) - /* no, track 0 failed after 77 steps */ - fdc->upd765_status[0] |= 0x40 | 0x10; - } - } - else - { - /* abnormal termination, not ready */ - fdc->upd765_status[0] |= 0x40 | 0x08; + case PHASE_RESULT: + msr |= MSR_RQM|MSR_DIO|MSR_CB; + break; } + for(int i=0; i<4; i++) + if(flopi[i].main_state == RECALIBRATE || flopi[i].main_state == SEEK) + msr |= 1<<i; - /* set drive and side. note: commented out side to avoid problems with the tf20 */ - fdc->upd765_status[0] |= fdc->drive; //| (fdc->side<<2); - - upd765_set_int(device,0); - upd765_set_int(device,1); - - fdc->upd765_flags &= ~UPD765_SEEK_ACTIVE; + if(data_irq) { + data_irq = false; + check_irq(); + } - upd765_idle(device); + return msr; } -static TIMER_CALLBACK(upd765_seek_timer_callback) +WRITE8_MEMBER(upd765_family_device::dsr_w) { - device_t *device = (device_t *)ptr; - upd765_t *fdc = get_safe_token(device); - /* seek complete */ - upd765_seek_complete(device); - - fdc->seek_timer->reset(); + dsr = data; + cur_rate = rates[dsr & 3]; } -static void upd765_timer_func(device_t *device, int timer_type) +void upd765_family_device::set_rate(int rate) { - upd765_t *fdc = get_safe_token(device); - /* type 0 = data transfer mode in execution phase */ - if (fdc->timer_type == 0) - { - /* set data request */ - upd765_set_data_request(device); + cur_rate = rate; +} - fdc->timer_type = 4; +READ8_MEMBER(upd765_family_device::fifo_r) +{ + UINT8 r = 0; + switch(main_phase) { + case PHASE_EXEC: + if(internal_drq) + return fifo_pop(false); + logerror("%s: fifo_r in phase %d\n", tag(), main_phase); + break; - if (!(fdc->upd765_flags & UPD765_DMA_MODE)) - { - if (fdc->upd765_command_bytes[0] & UPD765_MF) - { - /* MFM */ - fdc->timer->reset(attotime::from_usec(13)); - } - else - { - /* FM */ - fdc->timer->reset(attotime::from_usec(27)); - } - } - else - { - upd765_timer_func(device, fdc->timer_type); - } + case PHASE_RESULT: + r = result[0]; + result_pos--; + memmove(result, result+1, result_pos); + if(!result_pos) + main_phase = PHASE_CMD; + break; + default: + logerror("%s: fifo_r in phase %d\n", tag(), main_phase); + break; } - else if (fdc->timer_type==2) - { - /* result phase begin */ - - /* generate a int for specific commands */ - switch (fdc->command) { - case 2: /* read a track */ - case 5: /* write data */ - case 6: /* read data */ - case 9: /* write deleted data */ - case 10: /* read id */ - case 12: /* read deleted data */ - case 13: /* format at track */ - case 17: /* scan equal */ - case 19: /* scan low or equal */ - case 29: /* scan high or equal */ - upd765_set_int(device,1); - break; - default: + return r; +} + +WRITE8_MEMBER(upd765_family_device::fifo_w) +{ + switch(main_phase) { + case PHASE_CMD: { + command[command_pos++] = data; + int cmd = check_command(); + if(cmd == C_INCOMPLETE) break; + if(cmd == C_INVALID) { + logerror("%s: Invalid on %02x\n", tag(), command[0]); + exit(1); + command_pos = 0; + return; } - - upd765_set_data_request(device); - - fdc->timer->reset(); + start_command(cmd); + break; } - else if (fdc->timer_type == 4) - { - /* if in dma mode, a int is not generated per byte. If not in DMA mode - a int is generated per byte */ - if (fdc->upd765_flags & UPD765_DMA_MODE) - { - upd765_set_dma_drq(device,1); - } - else - { - if (fdc->FDC_main & (1<<7)) - { - /* set int to indicate data is ready */ - upd765_set_int(device,1); - } + case PHASE_EXEC: + if(internal_drq) { + fifo_push(data, false); + return; } + logerror("%s: fifo_w in phase %d\n", tag(), main_phase); + break; - fdc->timer->reset(); + default: + logerror("%s: fifo_w in phase %d\n", tag(), main_phase); + break; } } -static TIMER_CALLBACK(upd765_timer_callback) +UINT8 upd765_family_device::do_dir_r() { - device_t *device = (device_t *)ptr; - upd765_timer_func(device,param); + floppy_info &fi = flopi[dor & 3]; + if(fi.dev) + return fi.dev->dskchg_r() ? 0x00 : 0x80; + return 0x00; } -/* after (32-27) the DRQ is set, then 27 us later, the int is set. -I don't know if this is correct, but it is required for the PCW driver. -In this driver, the first NMI calls the handler function, furthur NMI's are -effectively disabled by reading the data before the NMI int can be set. -*/ - -static void upd765_setup_timed_generic(device_t *device, int timer_type, attotime duration) +READ8_MEMBER(upd765_family_device::dir_r) { - upd765_t *fdc = get_safe_token(device); - - fdc->timer_type = timer_type; - - if (!(fdc->upd765_flags & UPD765_DMA_MODE)) - { - fdc->timer->adjust(duration); - } - else - { - upd765_timer_func(device,fdc->timer_type); - fdc->timer->reset(); - } + return do_dir_r(); } -/* setup data request */ -static void upd765_setup_timed_data_request(device_t *device, int bytes) +WRITE8_MEMBER(upd765_family_device::ccr_w) { - /* setup timer to trigger in UPD765_DATA_RATE us */ - upd765_setup_timed_generic(device, 0, attotime::from_usec(32-27) /*UPD765_DATA_RATE)*bytes*/); + dsr = (dsr & 0xfc) | (data & 3); + cur_rate = rates[data & 3]; } -/* setup result data request */ -static void upd765_setup_timed_result_data_request(device_t *device) +void upd765_family_device::set_drq(bool state) { - upd765_setup_timed_generic(device, 2, attotime::from_usec(UPD765_DATA_RATE*2)); + if(state != drq) { + drq = state; + if(!drq_cb.isnull()) + drq_cb(drq); + } } - -/* sets up a timer to issue a seek complete in signed_tracks time */ -static void upd765_setup_timed_int(device_t *device,int signed_tracks) +bool upd765_family_device::get_drq() const { - upd765_t *fdc = get_safe_token(device); - /* setup timer to signal after seek time is complete */ - fdc->seek_timer->adjust(attotime::from_double(fdc->srt_in_ms*abs(signed_tracks)*0.001)); + return drq; } -static void upd765_seek_setup(device_t *device, int is_recalibrate) +void upd765_family_device::enable_transfer() { - device_t *img; - int signed_tracks; - upd765_t *fdc = get_safe_token(device); - - fdc->upd765_flags |= UPD765_SEEK_ACTIVE; - - if (is_recalibrate) - { - /* head cannot be specified with recalibrate */ - fdc->upd765_command_bytes[1] &=~0x04; - } - - upd765_setup_drive_and_side(device); - - img = current_image(device); - - fdc->FDC_main |= (1<<fdc->drive); - fdc->FDC_main |= 0x20; // execution phase - fdc->FDC_main &= ~0x10; // not busy, can send another seek/recalibrate - // for a different drive, or sense int status - - /* recalibrate command? */ - if (is_recalibrate) - { - fdc->upd765_flags |= UPD765_SEEK_OPERATION_IS_RECALIBRATE; - - fdc->ncn = 0; - - /* if drive is already at track 0, or drive is not ready */ - if (img == NULL || floppy_tk00_r(img) == CLEAR_LINE || (!upd765_get_rdy(device))) - { - /* seek completed */ -// upd765_seek_complete(device); - // delay for the time of 1 step, the PCW does not like immediate recalibrates - upd765_setup_timed_int(device,1); + if(spec & SPEC_ND) { + // PIO + if(!internal_drq) { + internal_drq = true; + check_irq(); } - else - { - /* is drive present? */ - if (1) //image_slotexists(img)) //fix me - { - /* yes - calculate real number of tracks to seek */ - - int current_track; - - /* get current track */ - current_track = floppy_drive_get_current_track(img); - - /* get number of tracks to seek */ - signed_tracks = -current_track; - } - else - { - /* no, seek 77 tracks and then stop */ - /* true for UPD765A, but not for other variants */ - signed_tracks = -77; - } - - /* perform seek - if drive isn't present it will not do anything */ - floppy_drive_seek(img, signed_tracks); - if (signed_tracks!=0) - { - upd765_setup_timed_int(device,signed_tracks); - } - else - { - upd765_seek_complete(device); - } - } + } else { + // DMA + if(!drq) + set_drq(true); } - else - { - - fdc->upd765_flags &= ~UPD765_SEEK_OPERATION_IS_RECALIBRATE; - - fdc->ncn = fdc->upd765_command_bytes[2]; - - /* get signed tracks */ - signed_tracks = fdc->ncn - fdc->pcn[fdc->drive]; - - /* perform seek - if drive isn't present it will not do anything */ - floppy_drive_seek(img, signed_tracks); - - /* if no tracks to seek, or drive is not ready, seek is complete */ - if (img == NULL || (signed_tracks==0) || (!upd765_get_rdy(device))) - { - upd765_seek_complete(device); - } - else - { - /* seek complete - issue an interrupt */ - upd765_setup_timed_int(device,signed_tracks); - } - } -// upd765_idle(device); } - - -static void upd765_setup_execution_phase_read(device_t *device, char *ptr, int size) +void upd765_family_device::disable_transfer() { - upd765_t *fdc = get_safe_token(device); - -// fdc->FDC_main &= ~0x040; /* FDC->CPU */ - fdc->FDC_main |= 0x040; /* FDC->CPU */ - - fdc->upd765_transfer_bytes_count = 0; - fdc->upd765_transfer_bytes_remaining = size; - fdc->execution_phase_data = ptr; - fdc->upd765_phase = UPD765_EXECUTION_PHASE_READ; - - upd765_setup_timed_data_request(device, 1); + if(spec & SPEC_ND) { + internal_drq = false; + check_irq(); + } else + set_drq(false); } -static void upd765_setup_execution_phase_write(device_t *device, char *ptr, int size) +void upd765_family_device::fifo_push(UINT8 data, bool internal) { - upd765_t *fdc = get_safe_token(device); - - fdc->FDC_main &= ~0x040; /* FDC->CPU */ - - fdc->upd765_transfer_bytes_count = 0; - fdc->upd765_transfer_bytes_remaining = size; - fdc->execution_phase_data = ptr; - fdc->upd765_phase = UPD765_EXECUTION_PHASE_WRITE; - - /* setup a data request with first byte */ - upd765_setup_timed_data_request(device,1); + if(fifo_pos == 16) { + if(internal) + st1 |= ST1_OR; + return; + } + fifo[fifo_pos++] = data; + fifo_expected--; + + int thr = (fifocfg & FIF_THR)+1; + if(!fifo_write && (!fifo_expected || fifo_pos >= thr || (fifocfg & FIF_DIS))) + enable_transfer(); + if(fifo_write && (fifo_pos == 16 || !fifo_expected)) + disable_transfer(); } -static void upd765_setup_result_phase(device_t *device, int byte_count) +UINT8 upd765_family_device::fifo_pop(bool internal) { - upd765_t *fdc = get_safe_token(device); - - fdc->FDC_main |= 0x040; /* FDC->CPU */ - fdc->FDC_main &= ~0x020; /* not execution phase */ - - fdc->upd765_transfer_bytes_count = 0; - fdc->upd765_transfer_bytes_remaining = byte_count; - fdc->upd765_phase = UPD765_RESULT_PHASE; - - upd765_setup_timed_result_data_request(device); + if(!fifo_pos) { + if(internal) + st1 |= ST1_OR; + return 0; + } + UINT8 r = fifo[0]; + fifo_pos--; + memmove(fifo, fifo+1, fifo_pos); + if(!fifo_write && !fifo_pos) + disable_transfer(); + int thr = fifocfg & 15; + if(fifo_write && fifo_expected && (fifo_pos <= thr || (fifocfg & 0x20))) + enable_transfer(); + return r; } -void upd765_idle(device_t *device) +void upd765_family_device::fifo_expect(int size, bool write) { - upd765_t *fdc = get_safe_token(device); - - fdc->FDC_main &= ~0x040; /* CPU->FDC */ - fdc->FDC_main &= ~0x020; /* not execution phase */ - fdc->FDC_main &= ~0x010; /* not busy */ - fdc->upd765_phase = UPD765_COMMAND_PHASE_FIRST_BYTE; - - upd765_set_data_request(device); + fifo_expected = size; + fifo_write = write; + if(fifo_write) + enable_transfer(); } - - -/* change flags */ -static void upd765_change_flags(device_t *device,unsigned int flags, unsigned int mask) +READ8_MEMBER(upd765_family_device::mdma_r) { - unsigned int new_flags; - unsigned int changed_flags; - upd765_t *fdc = get_safe_token(device); - - assert((flags & ~mask) == 0); - - /* compute the new flags and which ones have changed */ - new_flags = fdc->upd765_flags & ~mask; - new_flags |= flags; - changed_flags = fdc->upd765_flags ^ new_flags; - fdc->upd765_flags = new_flags; - - /* if interrupt changed, call the handler */ - if (changed_flags & UPD765_INT) - fdc->out_int_func((fdc->upd765_flags & UPD765_INT) ? 1 : 0); - - /* if DRQ changed, call the handler */ - if (changed_flags & UPD765_DMA_DRQ) - fdc->out_drq_func((fdc->upd765_flags & UPD765_DMA_DRQ) ? 1 : 0); + return dma_r(); } - - -/* set int output */ -static void upd765_set_int(device_t *device, int state) +WRITE8_MEMBER(upd765_family_device::mdma_w) { - if (LOG_INTERRUPT) - logerror("upd765_set_int(): state=%d\n", state); - upd765_change_flags(device, state ? UPD765_INT : 0, UPD765_INT); + dma_w(data); } - - -/* set dma request output */ -static void upd765_set_dma_drq(device_t *device, int state) +UINT8 upd765_family_device::dma_r() { - upd765_change_flags(device, state ? UPD765_DMA_DRQ : 0, UPD765_DMA_DRQ); + return fifo_pop(false); } -READ_LINE_DEVICE_HANDLER( upd765_int_r ) +void upd765_family_device::dma_w(UINT8 data) { - upd765_t *fdc = get_safe_token(device); - - return (fdc->upd765_flags & UPD765_INT) ? 1 : 0; + fifo_push(data, false); } -READ_LINE_DEVICE_HANDLER( upd765_drq_r ) +void upd765_family_device::live_start(floppy_info &fi, int state) { - upd765_t *fdc = get_safe_token(device); + cur_live.tm = machine().time(); + cur_live.state = state; + cur_live.next_state = -1; + cur_live.fi = &fi; + cur_live.shift_reg = 0; + cur_live.crc = 0xffff; + cur_live.bit_counter = 0; + cur_live.data_separator_phase = false; + cur_live.data_reg = 0; + cur_live.previous_type = live_info::PT_NONE; + cur_live.data_bit_context = false; + cur_live.byte_counter = 0; + cur_live.pll.reset(cur_live.tm); + cur_live.pll.set_clock(attotime::from_hz(cur_rate*2)); + checkpoint_live = cur_live; + fi.live = true; - return (fdc->upd765_flags & UPD765_DMA_DRQ) ? 1 : 0; + live_run(); } - -/* Drive ready */ - -/* - -A drive will report ready if: -- drive is selected -- disc is in the drive -- disk is rotating at a constant speed (normally 300rpm) - -On more modern PCs, a ready signal is not provided by the drive. -This signal is not used in the PC design and was eliminated to save costs -If you look at the datasheets for the modern UPD765 variants, you will see the Ready -signal is not mentioned. - -On the original UPD765A, ready signal is required, and some commands will fail if the drive -is not ready. - - - - -*/ - - - - -/* done when ready state of drive changes */ -/* this ignores if command is active, in which case command should terminate immediatly -with error */ -static void upd765_set_ready_change_callback(device_t *controller, device_t *img, int state) +void upd765_family_device::checkpoint() { - upd765_t *fdc = get_safe_token(controller); - int drive = floppy_get_drive(img); - - if (LOG_EXTRA) - logerror("upd765: ready state change\n"); - - /* drive that changed state */ - fdc->upd765_status[0] = 0x0c0 | drive; - - /* not ready */ - if (state==0 && fdc->intf->rdy_pin == UPD765_RDY_PIN_CONNECTED ) - fdc->upd765_status[0] |= 8; - - /* trigger an int */ - upd765_set_int(controller, 1); + if(cur_live.fi) + cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); + checkpoint_live = cur_live; } - -/* terminal count input */ -WRITE_LINE_DEVICE_HANDLER( upd765_tc_w ) +void upd765_family_device::rollback() { - int old_state; - upd765_t *fdc = get_safe_token(device); - - old_state = fdc->upd765_flags; - - /* clear drq */ - upd765_set_dma_drq(device, 0); - - fdc->upd765_flags &= ~UPD765_TC; - if (state) - { - fdc->upd765_flags |= UPD765_TC; - } - - /* changed state? */ - if (((fdc->upd765_flags^old_state) & UPD765_TC)!=0) - { - /* now set? */ - if ((fdc->upd765_flags & UPD765_TC)!=0) - { - /* yes */ - if (fdc->timer) - { - if (fdc->timer_type==0) - { - fdc->timer->reset(); - - - } - } - -#ifdef NO_END_OF_CYLINDER - fdc->command_timer->adjust(attotime::zero); -#else - upd765_update_state(device); -#endif - } - } + cur_live = checkpoint_live; } -READ8_DEVICE_HANDLER( upd765_status_r ) +void upd765_family_device::live_delay(int state) { - upd765_t *fdc = get_safe_token(device); - if (LOG_EXTRA) - logerror("%s: upd765_status_r: %02x\n", space.machine().describe_context(), fdc->FDC_main); - return fdc->FDC_main; + cur_live.next_state = state; + if(cur_live.tm != machine().time()) + cur_live.fi->tm->adjust(cur_live.tm - machine().time()); + else + live_sync(); } - -/* control mark handling code */ - -/* if SK==1, and we are executing a read data command, and a deleted data mark is found, -skip it. -if SK==1, and we are executing a read deleted data command, and a data mark is found, -skip it. */ - -static int upd765_read_skip_sector(device_t *device) +void upd765_family_device::live_sync() { - upd765_t *fdc = get_safe_token(device); - /* skip set? */ - if ((fdc->upd765_command_bytes[0] & (1<<5))!=0) - { - /* read data? */ - if (fdc->command == 0x06) - { - /* did we just find a sector with deleted data mark? */ - if (fdc->data_type == UPD765_DAM_DELETED_DATA) - { - /* skip it */ - return TRUE; + if(!cur_live.tm.is_never()) { + if(cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); + } else { + cur_live.pll.commit(cur_live.fi->dev, cur_live.tm); + if(cur_live.next_state != -1) { + cur_live.state = cur_live.next_state; + cur_live.next_state = -1; } - } - /* deleted data? */ - else - if (fdc->command == 0x0c) - { - /* did we just find a sector with data mark ? */ - if (fdc->data_type == UPD765_DAM_DATA) - { - /* skip it */ - return TRUE; + if(cur_live.state == IDLE) { + cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); + cur_live.tm = attotime::never; + cur_live.fi->live = false; + cur_live.fi = 0; } } + cur_live.next_state = -1; + checkpoint(); } - - /* do not skip */ - return FALSE; } -/* this is much closer to how the upd765 actually gets sectors */ -/* used by read data, read deleted data, write data, write deleted data */ -/* What the upd765 does: - - - get next sector id from disc - - if sector id matches id specified in command, it will - search for next data block and read data from it. - - - if the index is seen twice while it is searching for a sector, then the sector cannot be found -*/ - -static void upd765_get_next_id(device_t *device, chrn_id *id) +void upd765_family_device::live_abort() { - upd765_t *fdc = get_safe_token(device); - device_t *img = current_image(device); - - /* get next id from disc */ - floppy_drive_get_next_id(img, fdc->side,id); - - fdc->sector_id = id->data_id; - - /* set correct data type */ - fdc->data_type = UPD765_DAM_DATA; - if (id->flags & ID_FLAG_DELETED_DATA) - { - fdc->data_type = UPD765_DAM_DELETED_DATA; + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); } -} - -static int upd765_get_matching_sector(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); - device_t *img = current_image(device); - chrn_id id; - - /* number of times we have seen index hole */ - int index_count = 0; - if (fdc->upd765_flags & UPD765_BAD_MEDIA) { - fdc->upd765_status[1] |= 1; - return FALSE; + if(cur_live.fi) { + cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); + cur_live.fi->live = false; + cur_live.fi = 0; } - /* get sector id's */ - do - { - upd765_get_next_id(device, &id); - - /* tested on Amstrad CPC - All bytes must match, otherwise - a NO DATA error is reported */ - if (id.R == fdc->upd765_command_bytes[4]) - { - if (id.C == fdc->upd765_command_bytes[2]) - { - if (id.H == fdc->upd765_command_bytes[3]) - { - if (id.N == fdc->upd765_command_bytes[5]) - { - /* end of cylinder is set if: - 1. sector data is read completely (i.e. no other errors occur like - no data. - 2. sector being read is same specified by EOT - 3. terminal count is not received */ - if (fdc->upd765_command_bytes[4]==fdc->upd765_command_bytes[6]) - { - /* set end of cylinder */ - fdc->upd765_status[1] |= UPD765_ST1_END_OF_CYLINDER; - } - - return TRUE; - } - } - } - else - { - /* the specified sector ID was found, however, the C value specified - in the read/write command did not match the C value read from the disc */ - - /* no data - checked on Amstrad CPC */ - fdc->upd765_status[1] |= UPD765_ST1_NO_DATA; - /* bad C value */ - fdc->upd765_status[2] |= UPD765_ST2_WRONG_CYLINDER; - - if (id.C == 0x0ff) - { - /* the C value is 0x0ff which indicates a bad track in the IBM soft-sectored - format */ - fdc->upd765_status[2] |= UPD765_ST2_BAD_CYLINDER; - } + cur_live.tm = attotime::never; + cur_live.state = IDLE; + cur_live.next_state = -1; +} - return FALSE; - } - } +void upd765_family_device::live_run(attotime limit) +{ + if(cur_live.state == IDLE || cur_live.next_state != -1) + return; - /* index set? */ - if (floppy_drive_get_flag_state(img, FLOPPY_DRIVE_INDEX)) - { - index_count++; + if(limit == attotime::never) { + if(cur_live.fi->dev) + limit = cur_live.fi->dev->time_next_index(); + if(limit == attotime::never) { + // Happens when there's no disk or if the fdc is not + // connected to a drive, hence no index pulse. Force a + // sync from time to time in that case, so that the main + // cpu timeout isn't too painful. Avoids looping into + // infinity looking for data too. + + limit = machine().time() + attotime::from_msec(1); + cur_live.fi->tm->adjust(attotime::from_msec(1)); } - } - while (index_count!=2); - if (fdc->upd765_command_bytes[4] != fdc->upd765_command_bytes[6]) - { - /* no data - specified sector ID was not found */ - fdc->upd765_status[1] |= UPD765_ST1_NO_DATA; - } + for(;;) { - return 0; -} - -static void upd765_read_complete(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); -/* causes problems!!! - need to fix */ -#ifdef NO_END_OF_CYLINDER - /* set end of cylinder */ - fdc->upd765_status[1] &= ~UPD765_ST1_END_OF_CYLINDER; -#else - /* completed read command */ + switch(cur_live.state) { + case SEARCH_ADDRESS_MARK_HEADER: + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); +#endif - /* end of cylinder is set when: - - a whole sector has been read - - terminal count input is not set - - AND the the sector specified by EOT was read - */ + if(cur_live.shift_reg == 0x4489) { + cur_live.crc = 0x443b; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_HEADER_BLOCK_HEADER; + } + break; - /* if end of cylinder is set, and we did receive a terminal count, then clear it */ - if ((fdc->upd765_flags & UPD765_TC)!=0) - { - /* set end of cylinder */ - fdc->upd765_status[1] &= ~UPD765_ST1_END_OF_CYLINDER; - } + case READ_HEADER_BLOCK_HEADER: { + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); #endif + if(cur_live.bit_counter & 15) + break; + + int slot = cur_live.bit_counter >> 4; - upd765_setup_st0(device); + if(slot < 3) { + if(cur_live.shift_reg != 0x4489) + cur_live.state = SEARCH_ADDRESS_MARK_HEADER; + break; + } + if(cur_live.data_reg != 0xfe) { + cur_live.state = SEARCH_ADDRESS_MARK_HEADER; + break; + } - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - fdc->upd765_result_bytes[1] = fdc->upd765_status[1]; - fdc->upd765_result_bytes[2] = fdc->upd765_status[2]; - fdc->upd765_result_bytes[3] = fdc->upd765_command_bytes[2]; /* C */ - fdc->upd765_result_bytes[4] = fdc->upd765_command_bytes[3]; /* H */ - fdc->upd765_result_bytes[5] = fdc->upd765_command_bytes[4]; /* R */ - fdc->upd765_result_bytes[6] = fdc->upd765_command_bytes[5]; /* N */ + cur_live.bit_counter = 0; + cur_live.state = READ_ID_BLOCK; - upd765_setup_result_phase(device,7); -} + break; + } -static void upd765_read_data(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); - device_t *img = current_image(device); + case READ_ID_BLOCK: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + int slot = (cur_live.bit_counter >> 4)-1; + + if(0) + fprintf(stderr, "%s: slot=%d data=%02x crc=%04x\n", tts(cur_live.tm).cstr(), slot, cur_live.data_reg, cur_live.crc); + cur_live.idbuf[slot] = cur_live.data_reg; + if(slot == 5) { + live_delay(IDLE); + return; + } + break; + } - if (!upd765_get_rdy(device)) - { - fdc->upd765_status[0] = 0x0c0 | (1<<4) | fdc->drive | (fdc->side<<2); - fdc->upd765_status[1] = 0x00; - fdc->upd765_status[2] = 0x00; + case SEARCH_ADDRESS_MARK_DATA: + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter >> 4, cur_live.bit_counter & 15); +#endif + // Large tolerance due to perpendicular recording at extended density + if(cur_live.bit_counter > 62*16) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; + } - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - fdc->upd765_result_bytes[1] = fdc->upd765_status[1]; - fdc->upd765_result_bytes[2] = fdc->upd765_status[2]; - fdc->upd765_result_bytes[3] = fdc->upd765_command_bytes[2]; /* C */ - fdc->upd765_result_bytes[4] = fdc->upd765_command_bytes[3]; /* H */ - fdc->upd765_result_bytes[5] = fdc->upd765_command_bytes[4]; /* R */ - fdc->upd765_result_bytes[6] = fdc->upd765_command_bytes[5]; /* N */ - upd765_setup_result_phase(device,7); - return; - } + if(cur_live.bit_counter >= 28*16 && cur_live.shift_reg == 0x4489) { + cur_live.crc = 0x443b; + cur_live.data_separator_phase = false; + cur_live.bit_counter = 0; + cur_live.state = READ_DATA_BLOCK_HEADER; + } + break; - if (LOG_VERBOSE) - logerror("sector c: %02x h: %02x r: %02x n: %02x\n",fdc->upd765_command_bytes[2], fdc->upd765_command_bytes[3],fdc->upd765_command_bytes[4], fdc->upd765_command_bytes[5]); - - /* find a sector to read data from */ - { - int found_sector_to_read; - - found_sector_to_read = 0; - /* check for finished reading sectors */ - do - { - /* get matching sector */ - if (upd765_get_matching_sector(device)) - { - - /* skip it? */ - if (upd765_read_skip_sector(device)) - { - /* yes */ - - /* check that we haven't finished reading all sectors */ - if (upd765_sector_count_complete(device)) - { - /* read complete */ - upd765_read_complete(device); - return; - } + case READ_DATA_BLOCK_HEADER: { + if(read_one_bit(limit)) + return; +#if 0 + fprintf(stderr, "%s: shift = %04x data=%02x counter=%d\n", tts(cur_live.tm).cstr(), cur_live.shift_reg, + (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) | + (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) | + (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) | + (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) | + (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) | + (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) | + (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) | + (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00), + cur_live.bit_counter); +#endif + if(cur_live.bit_counter & 15) + break; - /* read not finished */ + int slot = cur_live.bit_counter >> 4; - /* increment sector count */ - upd765_increment_sector(device); - } - else - { - /* found a sector to read */ - found_sector_to_read = 1; + if(slot < 3) { + if(cur_live.shift_reg != 0x4489) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); + return; } + break; } - else - { - /* error in finding sector */ - upd765_read_complete(device); + if(cur_live.data_reg != 0xfb && cur_live.data_reg != 0xfd) { + live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED); return; } - } - while (found_sector_to_read==0); - } - - { - int data_size; - - data_size = upd765_n_to_bytes(fdc->upd765_command_bytes[5]); - - floppy_drive_read_sector_data(img, fdc->side, fdc->sector_id,fdc->data_buffer,data_size); - - upd765_setup_execution_phase_read(device,fdc->data_buffer, data_size); - } -} + cur_live.bit_counter = 0; + cur_live.state = READ_SECTOR_DATA; + break; + } -static void upd765_format_track(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); - device_t *img = current_image(device); + case SEARCH_ADDRESS_MARK_DATA_FAILED: + st1 |= ST1_MA; + st2 |= ST2_MD; + cur_live.state = IDLE; + return; - /* write protected? */ - if (floppy_wpt_r(img) == CLEAR_LINE) - { - fdc->upd765_status[1] |= UPD765_ST1_NOT_WRITEABLE; + case READ_SECTOR_DATA: { + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter & 15) + break; + int slot = (cur_live.bit_counter >> 4)-1; + if(slot < sector_size) { + // Sector data + live_delay(READ_SECTOR_DATA_BYTE); + return; - upd765_setup_st0(device); - /* TODO: Check result is correct */ - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - fdc->upd765_result_bytes[1] = fdc->upd765_status[1]; - fdc->upd765_result_bytes[2] = fdc->upd765_status[2]; - fdc->upd765_result_bytes[3] = fdc->format_data[0]; - fdc->upd765_result_bytes[4] = fdc->format_data[1]; - fdc->upd765_result_bytes[5] = fdc->format_data[2]; - fdc->upd765_result_bytes[6] = fdc->format_data[3]; - upd765_setup_result_phase(device,7); + } else if(slot < sector_size+2) { + // CRC + if(slot == sector_size+1) { + live_delay(IDLE); + return; + } + } + break; + } - return; - } + case READ_SECTOR_DATA_BYTE: + if(!tc_done) + fifo_push(cur_live.data_reg, true); + cur_live.state = READ_SECTOR_DATA; + checkpoint(); + break; - upd765_setup_execution_phase_write(device, &fdc->format_data[0], 4); -} + case WRITE_SECTOR_SKIP_GAP2: + cur_live.bit_counter = 0; + cur_live.byte_counter = 0; + cur_live.state = WRITE_SECTOR_SKIP_GAP2_BYTE; + checkpoint(); + break; -static void upd765_read_a_track(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); - int data_size; + case WRITE_SECTOR_SKIP_GAP2_BYTE: + if(read_one_bit(limit)) + return; + if(cur_live.bit_counter != 22*16) + break; + cur_live.bit_counter = 0; + cur_live.byte_counter = 0; + live_delay(WRITE_SECTOR_DATA); + return; + + case WRITE_SECTOR_DATA: + if(cur_live.byte_counter < 12) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 15) + live_write_raw(0x4489); + else if(cur_live.byte_counter < 16) { + cur_live.crc = 0xcdb4; + live_write_mfm(command[0] & 0x08 ? 0xf8 : 0xfb); + } else if(cur_live.byte_counter < 16+sector_size) + live_write_mfm(tc_done && !fifo_pos? 0x00 : fifo_pop(true)); + else if(cur_live.byte_counter < 16+sector_size+2) + live_write_mfm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 16+sector_size+2+command[7]) + live_write_mfm(0x4e); + else { + cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm); + cur_live.state = IDLE; + return; + } + cur_live.state = WRITE_SECTOR_DATA_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; - /* SKIP not allowed with this command! */ + case WRITE_TRACK_PRE_SECTORS: + if(!cur_live.byte_counter && command[3]) + fifo_expect(4, true); + if(cur_live.byte_counter < 80) + live_write_mfm(0x4e); + else if(cur_live.byte_counter < 92) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 95) + live_write_raw(0x5224); + else if(cur_live.byte_counter < 96) + live_write_mfm(0xfc); + else if(cur_live.byte_counter < 146) + live_write_mfm(0x4e); + else { + cur_live.state = WRITE_TRACK_SECTOR; + cur_live.byte_counter = 0; + break; + } + cur_live.state = WRITE_TRACK_PRE_SECTORS_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; - /* get next id */ - chrn_id id; + case WRITE_TRACK_SECTOR: + if(!cur_live.byte_counter) { + command[3]--; + if(command[3]) + fifo_expect(4, true); + } + if(cur_live.byte_counter < 12) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 15) + live_write_raw(0x4489); + else if(cur_live.byte_counter < 16) { + cur_live.crc = 0xcdb4; + live_write_mfm(0xfe); + } else if(cur_live.byte_counter < 20) + live_write_mfm(fifo_pop(true)); + else if(cur_live.byte_counter < 22) + live_write_mfm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 44) + live_write_mfm(0x4e); + else if(cur_live.byte_counter < 56) + live_write_mfm(0x00); + else if(cur_live.byte_counter < 59) + live_write_raw(0x4489); + else if(cur_live.byte_counter < 60) { + cur_live.crc = 0xcdb4; + live_write_mfm(0xfb); + } else if(cur_live.byte_counter < 60+sector_size) + live_write_mfm(command[5]); + else if(cur_live.byte_counter < 62+sector_size) + live_write_mfm(cur_live.crc >> 8); + else if(cur_live.byte_counter < 62+sector_size+command[4]) + live_write_mfm(0x4e); + else { + cur_live.byte_counter = 0; + cur_live.state = command[3] ? WRITE_TRACK_SECTOR : WRITE_TRACK_POST_SECTORS; + break; + } + cur_live.state = WRITE_TRACK_SECTOR_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; - upd765_get_next_id(device, &id); + case WRITE_TRACK_POST_SECTORS: + live_write_mfm(0x4e); + cur_live.state = WRITE_TRACK_POST_SECTORS_BYTE; + cur_live.bit_counter = 16; + checkpoint(); + break; - /* TO BE CONFIRMED! */ - /* check id from disc */ - if (id.C==fdc->upd765_command_bytes[2]) - { - if (id.H==fdc->upd765_command_bytes[3]) - { - if (id.R==fdc->upd765_command_bytes[4]) - { - if (id.N==fdc->upd765_command_bytes[5]) - { - /* if ID found, then no data is not set */ - /* otherwise no data will remain set */ - fdc->upd765_status[1] &=~UPD765_ST1_NO_DATA; - } + case WRITE_TRACK_PRE_SECTORS_BYTE: + case WRITE_TRACK_SECTOR_BYTE: + case WRITE_TRACK_POST_SECTORS_BYTE: + case WRITE_SECTOR_DATA_BYTE: + if(write_one_bit(limit)) + return; + if(cur_live.bit_counter == 0) { + cur_live.byte_counter++; + live_delay(cur_live.state-1); + return; } + break; + + default: + logerror("%s: Unknown live state %d\n", tts(cur_live.tm).cstr(), cur_live.state); + return; } } - - - data_size = upd765_n_to_bytes(id.N); - - floppy_drive_read_sector_data(current_image(device), fdc->side, fdc->sector_id,fdc->data_buffer,data_size); - - upd765_setup_execution_phase_read(device,fdc->data_buffer, data_size); } -static int upd765_just_read_last_sector_on_track(device_t *device) +int upd765_family_device::check_command() { - if (floppy_drive_get_flag_state(current_image(device), FLOPPY_DRIVE_INDEX)) - return 1; - return 0; -} + // 0.000010 read track + // 00000011 specify + // 00000100 sense drive status + // ..000101 write data + // ...00110 read data + // 00000111 recalibrate + // 00001000 sense interrupt status + // ..001001 write deleted data + // 0.001010 read id + // ...01100 read deleted data + // 0.001101 format track + // 00001110 dumpreg + // 00001111 seek + // 00010000 version + // ...10001 scan equal + // 00010010 perpendicular mode + // 00010011 configure + // .0010100 lock + // ...10110 verify + // ...11001 scan low or equal + // ...11101 scan high or equal + // 1.001111 relative seek -static void upd765_write_complete(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); + // MSDOS 6.22 format uses 0xcd to format a track, which makes one + // think only the bottom 5 bits are decoded. -/* causes problems!!! - need to fix */ -#ifdef NO_END_OF_CYLINDER - /* set end of cylinder */ - fdc->upd765_status[1] &= ~UPD765_ST1_END_OF_CYLINDER; -#else - /* completed read command */ + switch(command[0] & 0x1f) { + case 0x02: + return command_pos == 9 ? C_READ_TRACK : C_INCOMPLETE; - /* end of cylinder is set when: - - a whole sector has been read - - terminal count input is not set - - AND the the sector specified by EOT was read - */ + case 0x03: + return command_pos == 3 ? C_SPECIFY : C_INCOMPLETE; - /* if end of cylinder is set, and we did receive a terminal count, then clear it */ - if ((fdc->upd765_flags & UPD765_TC)!=0) - { - /* set end of cylinder */ - fdc->upd765_status[1] &= ~UPD765_ST1_END_OF_CYLINDER; - } -#endif + case 0x04: + return command_pos == 2 ? C_SENSE_DRIVE_STATUS : C_INCOMPLETE; - upd765_setup_st0(device); + case 0x05: + case 0x09: + return command_pos == 9 ? C_WRITE_DATA : C_INCOMPLETE; - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - fdc->upd765_result_bytes[1] = fdc->upd765_status[1]; - fdc->upd765_result_bytes[2] = fdc->upd765_status[2]; - fdc->upd765_result_bytes[3] = fdc->upd765_command_bytes[2]; /* C */ - fdc->upd765_result_bytes[4] = fdc->upd765_command_bytes[3]; /* H */ - fdc->upd765_result_bytes[5] = fdc->upd765_command_bytes[4]; /* R */ - fdc->upd765_result_bytes[6] = fdc->upd765_command_bytes[5]; /* N */ + case 0x06: + case 0x0c: + return command_pos == 9 ? C_READ_DATA : C_INCOMPLETE; - upd765_setup_result_phase(device,7); -} + case 0x07: + return command_pos == 2 ? C_RECALIBRATE : C_INCOMPLETE; + case 0x08: + return C_SENSE_INTERRUPT_STATUS; -static void upd765_write_data(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); - if (!upd765_get_rdy(device)) - { - fdc->upd765_status[0] = 0x0c0 | (1<<4) | fdc->drive | (fdc->side<<2); - fdc->upd765_status[1] = 0x00; - fdc->upd765_status[2] = 0x00; - - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - fdc->upd765_result_bytes[1] = fdc->upd765_status[1]; - fdc->upd765_result_bytes[2] = fdc->upd765_status[2]; - fdc->upd765_result_bytes[3] = fdc->upd765_command_bytes[2]; /* C */ - fdc->upd765_result_bytes[4] = fdc->upd765_command_bytes[3]; /* H */ - fdc->upd765_result_bytes[5] = fdc->upd765_command_bytes[4]; /* R */ - fdc->upd765_result_bytes[6] = fdc->upd765_command_bytes[5]; /* N */ - upd765_setup_result_phase(device,7); - return; - } + case 0x0a: + return command_pos == 2 ? C_READ_ID : C_INCOMPLETE; - /* write protected? */ - if (floppy_wpt_r(current_image(device)) == CLEAR_LINE) - { - fdc->upd765_status[1] |= UPD765_ST1_NOT_WRITEABLE; + case 0x0d: + return command_pos == 6 ? C_FORMAT_TRACK : C_INCOMPLETE; - upd765_write_complete(device); - return; - } + case 0x0f: + return command_pos == 3 ? C_SEEK : C_INCOMPLETE; - if (upd765_get_matching_sector(device)) - { - int data_size; + case 0x12: + return command_pos == 2 ? C_PERPENDICULAR : C_INCOMPLETE; - data_size = upd765_n_to_bytes(fdc->upd765_command_bytes[5]); + case 0x13: + return command_pos == 4 ? C_CONFIGURE : C_INCOMPLETE; - upd765_setup_execution_phase_write(device,fdc->data_buffer, data_size); + default: + return C_INVALID; } - else - { - upd765_setup_result_phase(device,7); - } } +void upd765_family_device::start_command(int cmd) +{ + command_pos = 0; + result_pos = 0; + main_phase = PHASE_EXEC; + tc_done = false; + switch(cmd) { + case C_CONFIGURE: + logerror("%s: command configure %02x %02x %02x\n", + tag(), + command[1], command[2], command[3]); + // byte 1 is ignored, byte 3 is precompensation-related + fifocfg = command[2]; + main_phase = PHASE_CMD; + break; -/* return true if we have read all sectors, false if not */ -static int upd765_sector_count_complete(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); -/* this is not correct?? */ -#if 1 - /* if terminal count has been set - yes */ - if (fdc->upd765_flags & UPD765_TC) - { - /* completed */ - return 1; - } + case C_FORMAT_TRACK: + format_track_start(flopi[command[1] & 3]); + break; + case C_PERPENDICULAR: + logerror("%s: command perpendicular\n", tag()); + main_phase = PHASE_CMD; + break; + case C_READ_DATA: + read_data_start(flopi[command[1] & 3]); + break; - /* multi-track? */ - if (fdc->upd765_command_bytes[0] & UPD765_MT) - { - /* it appears that in multi-track mode, - the EOT parameter of the command is ignored!? - - or is it ignored the first time and not the next, so that - if it is started on side 0, it will end at EOT on side 1, - but if started on side 1 it will end at end of track???? + case C_READ_ID: + read_id_start(flopi[command[1] & 3]); + break; - PC driver requires this to end at last sector on side 1, and - ignore EOT parameter. + case C_READ_TRACK: + read_track_start(flopi[command[1] & 3]); + break; - To be checked!!!! - */ + case C_RECALIBRATE: + recalibrate_start(flopi[command[1] & 3]); + main_phase = PHASE_CMD; + break; - /* if just read last sector and on side 1 - finish */ - if (upd765_just_read_last_sector_on_track(device)) - { - if (floppy_get_heads_per_disk(flopimg_get_image(current_image(device)))==1) { - return 2; - } else { - if (fdc->side==1) - return 2; - return 1; // do not advance to next cylinder - } - } + case C_SEEK: + seek_start(flopi[command[1] & 3]); + main_phase = PHASE_CMD; + break; - /* if not on second side then we haven't finished yet */ - if (fdc->side!=1) - { - /* haven't finished yet */ - return 0; - } + case C_SENSE_DRIVE_STATUS: { + floppy_info &fi = flopi[command[1] & 3]; + main_phase = PHASE_RESULT; + result[0] = 0x08; + if(get_ready(fi.id)) + result[0] |= 0x20; + if(fi.dev) + result[0] |= + (fi.dev->wpt_r() ? 0x40 : 0x00) | + (fi.dev->trk00_r() ? 0x00 : 0x10) | + (fi.dev->ss_r() ? 0x04 : 0x00) | + (command[1] & 3); + logerror("%s: command sense drive status (%02x)\n", tag(), result[0]); + result_pos = 1; + break; } - else - { - /* sector id == EOT? */ - if (fdc->upd765_command_bytes[4]==fdc->upd765_command_bytes[6]) - { - /* completed */ - return 2; + case C_SENSE_INTERRUPT_STATUS: { + main_phase = PHASE_RESULT; + + int fid; + for(fid=0; fid<4 && !flopi[fid].irq_seek; fid++); + if(fid == 4) + for(fid=0; fid<4 && !flopi[fid].irq_polled; fid++); + if(fid == 4) { + st0 = ST0_UNK; + result[0] = st0; + result[1] = 0x00; + result_pos = 2; + logerror("%s: command sense interrupt status (%02x %02x)\n", tag(), result[0], result[1]); + break; } - } -#else + floppy_info &fi = flopi[fid]; + if(fi.irq_seek) + fi.irq_seek = false; + + else if(fi.irq_polled) { + // Documentation is somewhat contradictory w.r.t polling + // and irq. PC bios, especially 5150, requires that only + // one irq happens. That's also wait the ns82077a doc + // says it does. OTOH, a number of docs says you need to + // call SIS 4 times, once per drive... + // + // Let's take the option that allows PC to boot. + + for(int i=0; i<4; i++) + flopi[i].irq_polled = false; + + st0 = ST0_ABRT | fid; + } else { + abort(); + } + result[0] = st0; + result[1] = fi.pcn; + logerror("%s: command sense interrupt status (fid=%d %02x %02x)\n", tag(), fid, result[0], result[1]); + result_pos = 2; - /* if terminal count has been set - yes */ - if (fdc->upd765_flags & UPD765_TC) - { - /* completed */ - return 1; + check_irq(); + break; } - /* Multi-Track operation: - - Verified on Amstrad CPC. - - disc format used: - 9 sectors per track - 2 sides - Sector IDs: &01, &02, &03, &04, &05, &06, &07, &08, &09 - - Command specified: - SIDE = 0, - C = 0,H = 0,R = 1, N = 2, EOT = 1 - Sectors read: - Sector 1 side 0 - Sector 1 side 1 - - Command specified: - SIDE = 0, - C = 0,H = 0,R = 1, N = 2, EOT = 3 - Sectors read: - Sector 1 side 0 - Sector 2 side 0 - Sector 3 side 0 - Sector 1 side 1 - Sector 2 side 1 - Sector 3 side 1 - - - Command specified: - SIDE = 0, - C = 0, H = 0, R = 7, N = 2, EOT = 3 - Sectors read: - Sector 7 side 0 - Sector 8 side 0 - Sector 9 side 0 - Sector 10 not found. Error "No Data" - - Command specified: - SIDE = 1, - C = 0, H = 1, R = 1, N = 2, EOT = 1 - Sectors read: - Sector 1 side 1 - - Command specified: - SIDE = 1, - C = 0, H = 1, R = 1, N = 2, EOT = 2 - Sectors read: - Sector 1 side 1 - Sector 1 side 2 - - */ - - /* sector id == EOT? */ - if ((fdc->upd765_command_bytes[4]==fdc->upd765_command_bytes[6])) - { - /* multi-track? */ - if (fdc->upd765_command_bytes[0] & 0x080) - { - /* if we have reached EOT (fdc->upd765_command_bytes[6]) - on side 1, then read is complete */ - if (fdc->side==1) - return 1; - - return 0; + case C_SPECIFY: + logerror("%s: command specify %02x %02x\n", + tag(), + command[1], command[2]); + spec = (command[1] << 8) | command[2]; + main_phase = PHASE_CMD; + break; - } + case C_WRITE_DATA: + write_data_start(flopi[command[1] & 3]); + break; - /* completed */ - return 1; + default: + fprintf(stderr, "start command %d\n", cmd); + exit(1); } -#endif - /* not complete */ - return 0; } -static void upd765_increment_sector(device_t *device) +void upd765_family_device::command_end(floppy_info &fi, bool data_completion) { - upd765_t *fdc = get_safe_token(device); - - /* multi-track? */ - if (fdc->upd765_command_bytes[0] & UPD765_MT) - { - /* reached EOT? */ - if (fdc->upd765_command_bytes[4] == fdc->upd765_command_bytes[6]) - { - if (fdc->side == 1) - { - fdc->upd765_command_bytes[2]++; - } - - fdc->upd765_command_bytes[3] ^= 0x01; - fdc->upd765_command_bytes[4] = 1; - fdc->side = fdc->upd765_command_bytes[3] & 0x01; - } - else - { - fdc->upd765_command_bytes[4]++; - } - } + logerror("%s: command done (%s) -", tag(), data_completion ? "data" : "seek"); + for(int i=0; i != result_pos; i++) + logerror(" %02x", result[i]); + logerror("\n"); + fi.main_state = fi.sub_state = IDLE; + if(data_completion) + data_irq = true; else - { - if (fdc->upd765_command_bytes[4] == fdc->upd765_command_bytes[6]) - { - fdc->upd765_command_bytes[2]++; - fdc->upd765_command_bytes[4] = 1; - } - else - { - fdc->upd765_command_bytes[4]++; - } - } + fi.irq_seek = true; + check_irq(); } -/* control mark handling code */ - -/* if SK==0, and we are executing a read data command, and a deleted data sector is found, -the data is not skipped. The data is read, but the control mark is set and the read is stopped */ -/* if SK==0, and we are executing a read deleted data command, and a data sector is found, -the data is not skipped. The data is read, but the control mark is set and the read is stopped */ -static int upd765_read_data_stop(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); - /* skip not set? */ - if ((fdc->upd765_command_bytes[0] & (1<<5))==0) - { - /* read data? */ - if (fdc->command == 0x06) - { - /* did we just read a sector with deleted data? */ - if (fdc->data_type == UPD765_DAM_DELETED_DATA) - { - /* set control mark */ - fdc->upd765_status[2] |= UPD765_ST2_CONTROL_MARK; - - /* quit */ - return TRUE; - } - } - /* deleted data? */ - else - if (fdc->command == 0x0c) - { - /* did we just read a sector with data? */ - if (fdc->data_type == UPD765_DAM_DATA) - { - /* set control mark */ - fdc->upd765_status[2] |= UPD765_ST2_CONTROL_MARK; - - /* quit */ - return TRUE; - } - } - } - - /* continue */ - return FALSE; +void upd765_family_device::recalibrate_start(floppy_info &fi) +{ + logerror("%s: command recalibrate\n", tag()); + fi.main_state = RECALIBRATE; + fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; + fi.dir = 1; + fi.counter = 77; + seek_continue(fi); } -static TIMER_CALLBACK(upd765_continue_command) +void upd765_family_device::seek_start(floppy_info &fi) { - device_t *device = (device_t *)ptr; - upd765_t *fdc = get_safe_token(device); - if ((fdc->upd765_phase == UPD765_EXECUTION_PHASE_READ) || - (fdc->upd765_phase == UPD765_EXECUTION_PHASE_WRITE)) - { - switch (fdc->command) - { - /* read a track */ - case 0x02: - { - fdc->sector_counter++; - - /* sector counter == EOT */ - if (fdc->sector_counter==fdc->upd765_command_bytes[6]) - { - /* TODO: Add correct info here */ - - fdc->upd765_status[1] |= UPD765_ST1_END_OF_CYLINDER; - - upd765_setup_st0(device); - - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - fdc->upd765_result_bytes[1] = fdc->upd765_status[1]; - fdc->upd765_result_bytes[2] = fdc->upd765_status[2]; - fdc->upd765_result_bytes[3] = fdc->upd765_command_bytes[2]; /* C */ - fdc->upd765_result_bytes[4] = fdc->upd765_command_bytes[3]; /* H */ - fdc->upd765_result_bytes[5] = fdc->upd765_command_bytes[4]; /* R */ - fdc->upd765_result_bytes[6] = fdc->upd765_command_bytes[5]; /* N */ + logerror("%s: command %sseek %d\n", tag(), command[0] & 0x80 ? "relative " : "", command[2]); + fi.main_state = SEEK; + fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; + fi.dir = fi.pcn > command[2] ? 1 : 0; + seek_continue(fi); +} - upd765_setup_result_phase(device,7); - } - else - { - upd765_read_a_track(device); - } - } - break; +void upd765_family_device::delay_cycles(emu_timer *tm, int cycles) +{ + tm->adjust(attotime::from_double(double(cycles)/cur_rate)); +} - /* format track */ - case 0x0d: - { - floppy_drive_format_sector(current_image(device), fdc->side, fdc->sector_counter, - fdc->format_data[0], fdc->format_data[1], - fdc->format_data[2], fdc->format_data[3], - fdc->upd765_command_bytes[5]); - - fdc->sector_counter++; - - /* sector_counter = SC */ - if (fdc->sector_counter == fdc->upd765_command_bytes[3]) - { - /* TODO: Check result is correct */ - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - fdc->upd765_result_bytes[1] = fdc->upd765_status[1]; - fdc->upd765_result_bytes[2] = fdc->upd765_status[2]; - fdc->upd765_result_bytes[3] = fdc->format_data[0]; - fdc->upd765_result_bytes[4] = fdc->format_data[1]; - fdc->upd765_result_bytes[5] = fdc->format_data[2]; - fdc->upd765_result_bytes[6] = fdc->format_data[3]; - upd765_setup_result_phase(device,7); - } - else - { - upd765_format_track(device); - } +void upd765_family_device::seek_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case SEEK_MOVE: + if(fi.dev) { + fi.dev->dir_w(fi.dir); + fi.dev->stp_w(0); } - break; + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; + fi.tm->adjust(attotime::from_nsec(2500)); + return; - /* write data, write deleted data */ - case 0x09: - case 0x05: - { - /* sector id == EOT */ - UINT8 ddam; - - ddam = 0; - if (fdc->command == 0x09) - { - ddam = 1; - } + case SEEK_WAIT_STEP_SIGNAL_TIME: + return; - /* write data to disc */ - // logerror("floppy_drive_write_sector_data side=%d sector=%d tc=%x\n", fdc->side, fdc->sector_id, fdc->upd765_flags & UPD765_TC); - floppy_drive_write_sector_data(current_image(device), fdc->side, fdc->sector_id,fdc->data_buffer,upd765_n_to_bytes(fdc->upd765_command_bytes[5]),ddam); - - /* nothing to write */ - if ((fdc->upd765_transfer_bytes_remaining==0) && (fdc->upd765_flags & UPD765_DMA_MODE)) - { - if (fdc->upd765_flags & UPD765_TC) - { - upd765_write_complete(device); - break; - } - } + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + if(fi.dev) + fi.dev->stp_w(1); - if (upd765_sector_count_complete(device)) - { - upd765_increment_sector(device); - upd765_write_complete(device); - } + if(fi.main_state == SEEK) { + if(fi.pcn > command[2]) + fi.pcn--; else - { - upd765_increment_sector(device); - upd765_write_data(device); - } + fi.pcn++; } - break; - - /* read data, read deleted data */ - case 0x0c: - case 0x06: - { - - int cause; - /* read all sectors? */ - - /* sector id == EOT */ - if ((cause = upd765_sector_count_complete(device)) || upd765_read_data_stop(device)) - { - if (cause == 2) - upd765_increment_sector(device); // advance to next cylinder if EOT - - upd765_read_complete(device); - } - else - { - upd765_increment_sector(device); - upd765_read_data(device); + fi.sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(fi.tm, 500*(16-(spec >> 12))); + return; + + case SEEK_WAIT_STEP_TIME: + return; + + case SEEK_WAIT_STEP_TIME_DONE: { + bool done = false; + switch(fi.main_state) { + case RECALIBRATE: + fi.counter--; + done = !fi.dev || !fi.dev->trk00_r(); + if(done) + fi.pcn = 0; + else if(!fi.counter) { + st0 = ST0_FAIL|ST0_SE|ST0_EC; + command_end(fi, false); + return; } + break; + case SEEK: + done = fi.pcn == command[2]; + break; + } + if(done) { + st0 = ST0_SE; + command_end(fi, false); + return; } + fi.sub_state = SEEK_MOVE; break; - - default: - break; + } } } } - -static int upd765_get_command_byte_count(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); - fdc->command = fdc->upd765_command_bytes[0] & 0x01f; - - if (fdc->version==TYPE_UPD765A) - { - return upd765_cmd_size[fdc->command]; - } - else - { - if (fdc->version==TYPE_UPD72065) - { - switch(fdc->upd765_command_bytes[0]) - { - case 0x34: // Reset Standby - case 0x35: // Set Standby - case 0x36: // Software Reset - return 1; - default: - return upd765_cmd_size[fdc->command]; +void upd765_family_device::read_data_start(floppy_info &fi) +{ + fi.main_state = READ_DATA; + fi.sub_state = HEAD_LOAD_DONE; + logerror("%s: command read%s data%s%s%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + tag(), + command[0] & 0x08 ? " deleted" : "", + command[0] & 0x80 ? " mt" : "", + command[0] & 0x40 ? " mfm" : "", + command[0] & 0x20 ? " sk" : "", + fifocfg & 0x40 ? " seek" : "", + command[0], + command[1], + command[2], + command[3], + command[4], + 128 << (command[5] & 7), + command[6], + command[7], + command[8], + cur_rate); + + st0 = command[1] & 7; + st1 = ST1_MA; + st2 = 0x00; + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + read_data_continue(fi); +} + +void upd765_family_device::read_data_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + if(fi.pcn == command[2] || !(fifocfg & 0x40)) { + fi.sub_state = SEEK_DONE; + break; } - } - if (fdc->version==TYPE_SMC37C78) - { - switch (fdc->command) - { - /* version */ - case 0x010: - return 1; - - /* verify */ - case 0x016: - return 9; - - /* configure */ - case 0x013: - return 4; - - /* dumpreg */ - case 0x0e: - return 1; - - /* perpendicular mode */ - case 0x012: - return 1; - - /* lock */ - case 0x014: - return 1; - - /* seek/relative seek are together! */ - - default: - return upd765_cmd_size[fdc->command]; + st0 |= ST0_SE; + if(fi.dev) { + fi.dev->dir_w(fi.pcn > command[2] ? 1 : 0); + fi.dev->stp_w(0); } - } - } - - return upd765_cmd_size[fdc->command]; -} + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; + fi.tm->adjust(attotime::from_nsec(2500)); + return; + case SEEK_WAIT_STEP_SIGNAL_TIME: + return; + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + if(fi.dev) + fi.dev->stp_w(1); + fi.sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(fi.tm, 500*(16-(spec >> 12))); + return; + case SEEK_WAIT_STEP_TIME: + return; -void upd765_update_state(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); - switch (fdc->upd765_phase) { - case UPD765_RESULT_PHASE: - /* set data reg */ - fdc->upd765_data_reg = fdc->upd765_result_bytes[fdc->upd765_transfer_bytes_count]; + case SEEK_WAIT_STEP_TIME_DONE: + if(fi.pcn > command[2]) + fi.pcn--; + else + fi.pcn++; + fi.sub_state = HEAD_LOAD_DONE; + break; - if (fdc->upd765_transfer_bytes_count == 0) - { - /* clear int for specific commands */ - switch (fdc->command) { - case 2: /* read a track */ - case 5: /* write data */ - case 6: /* read data */ - case 9: /* write deleted data */ - case 10: /* read id */ - case 12: /* read deleted data */ - case 13: /* format at track */ - case 17: /* scan equal */ - case 19: /* scan low or equal */ - case 29: /* scan high or equal */ - upd765_set_int(device, 0); + case SEEK_DONE: + fi.counter = 0; + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(cur_live.crc) { + st0 |= ST0_FAIL; + st1 |= ST1_DE|ST1_ND; + fi.sub_state = COMMAND_DONE; break; + } + st1 &= ~ST1_MA; + if(!sector_matches()) { + if(cur_live.idbuf[0] != command[2]) { + if(cur_live.idbuf[0] == 0xff) + st2 |= ST2_WC|ST2_BC; + else + st2 |= ST2_WC; + st0 |= ST0_FAIL; + fi.sub_state = COMMAND_DONE; + break; + } + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + } + logerror("%s: reading sector %02x %02x %02x %02x\n", + tag(), + cur_live.idbuf[0], + cur_live.idbuf[1], + cur_live.idbuf[2], + cur_live.idbuf[3]); + sector_size = calc_sector_size(cur_live.idbuf[3]); + fifo_expect(sector_size, false); + fi.sub_state = SECTOR_READ; + live_start(fi, SEARCH_ADDRESS_MARK_DATA); + return; + + case SCAN_ID_FAILED: + st0 |= ST0_FAIL; + st1 |= ST1_ND; + fi.sub_state = COMMAND_DONE; + break; - default: + case SECTOR_READ: { + if(st2 & ST2_MD) { + st0 |= ST0_FAIL; + fi.sub_state = COMMAND_DONE; break; } + if(cur_live.crc) { + st0 |= ST0_FAIL; + st1 |= ST1_DE; + st2 |= ST2_CM; + fi.sub_state = COMMAND_DONE; + break; + } + bool done = tc_done; + command[4]++; + if(command[4] > command[6]) { + command[4] = 1; + if(command[0] & 0x80) { + command[3] = command[3] ^ 1; + if(fi.dev) + fi.dev->ss_w(command[3] & 1); + } + if(!(command[0] & 0x80) || !(command[3] & 1)) { + command[2]++; + if(!tc_done) { + st0 |= ST0_FAIL; + st1 |= ST1_EN; + } + done = true; + } + } + if(!done) { + fi.sub_state = SEEK_DONE; + break; + } + fi.sub_state = COMMAND_DONE; + break; } - if (LOG_VERBOSE) - logerror("UPD765: RESULT: %02x\n", fdc->upd765_data_reg); - - fdc->upd765_transfer_bytes_count++; - fdc->upd765_transfer_bytes_remaining--; - - if (fdc->upd765_transfer_bytes_remaining==0) - { - upd765_idle(device); - } - else - { - upd765_set_data_request(device); - } - break; - - case UPD765_EXECUTION_PHASE_READ: - /* setup data register */ - fdc->upd765_data_reg = fdc->execution_phase_data[fdc->upd765_transfer_bytes_count]; - fdc->upd765_transfer_bytes_count++; - fdc->upd765_transfer_bytes_remaining--; - - if (LOG_EXTRA) - logerror("EXECUTION PHASE READ: %02x\n", fdc->upd765_data_reg); - - if ((fdc->upd765_transfer_bytes_remaining==0) || (fdc->upd765_flags & UPD765_TC)) - { - fdc->command_timer->adjust(attotime::zero); - } - else - { - /* trigger int */ - upd765_setup_timed_data_request(device,1); - } - break; - - case UPD765_COMMAND_PHASE_FIRST_BYTE: - fdc->FDC_main |= 0x10; /* set BUSY */ - - if (LOG_VERBOSE) - logerror("%s: upd765(): command=0x%02x\n", device->machine().describe_context(), fdc->upd765_data_reg); - - /* seek in progress? */ - if (fdc->upd765_flags & UPD765_SEEK_ACTIVE) - { - /* any command results in a invalid - I think that seek, recalibrate and - sense interrupt status may work*/ - if (fdc->upd765_data_reg != 8) /* Sense Interrupt Status */ - fdc->upd765_data_reg = 0; - } - - fdc->upd765_command_bytes[0] = fdc->upd765_data_reg; - - fdc->upd765_transfer_bytes_remaining = upd765_get_command_byte_count(device); - - fdc->upd765_transfer_bytes_count = 1; - fdc->upd765_transfer_bytes_remaining--; - - if (fdc->upd765_transfer_bytes_remaining==0) - { - upd765_setup_command(device); - } - else - { - /* request more data */ - upd765_set_data_request(device); - fdc->upd765_phase = UPD765_COMMAND_PHASE_BYTES; - } - break; - - case UPD765_COMMAND_PHASE_BYTES: - if (LOG_VERBOSE) - logerror("%s: upd765(): command=0x%02x\n", device->machine().describe_context(), fdc->upd765_data_reg); - - fdc->upd765_command_bytes[fdc->upd765_transfer_bytes_count] = fdc->upd765_data_reg; - fdc->upd765_transfer_bytes_count++; - fdc->upd765_transfer_bytes_remaining--; - - if (fdc->upd765_transfer_bytes_remaining==0) - { - upd765_setup_command(device); - } - else - { - /* request more data */ - upd765_set_data_request(device); - } - break; - - case UPD765_EXECUTION_PHASE_WRITE: - fdc->execution_phase_data[fdc->upd765_transfer_bytes_count]=fdc->upd765_data_reg; - fdc->upd765_transfer_bytes_count++; - fdc->upd765_transfer_bytes_remaining--; + case COMMAND_DONE: + main_phase = PHASE_RESULT; + result[0] = st0; + result[1] = st1; + result[2] = st2; + result[3] = command[2]; + result[4] = command[3]; + result[5] = command[4]; + result[6] = command[5]; + result_pos = 7; + command_end(fi, true); + return; - if ((fdc->upd765_transfer_bytes_remaining == 0) || (fdc->upd765_flags & UPD765_TC)) - { - fdc->command_timer->adjust(attotime::zero); - } - else - { - upd765_setup_timed_data_request(device,1); + default: + logerror("%s: read sector unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + return; } - break; } } +void upd765_family_device::write_data_start(floppy_info &fi) +{ + fi.main_state = WRITE_DATA; + fi.sub_state = HEAD_LOAD_DONE; + logerror("%s: command write%s data%s%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + tag(), + command[0] & 0x08 ? " deleted" : "", + command[0] & 0x80 ? " mt" : "", + command[0] & 0x40 ? " mfm" : "", + command[0], + command[1], + command[2], + command[3], + command[4], + 128 << (command[5] & 7), + command[6], + command[7], + command[8], + cur_rate); + + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + + st0 = command[1] & 7; + st1 = ST1_MA; + st2 = 0x00; + + write_data_continue(fi); +} + +void upd765_family_device::write_data_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + fi.counter = 0; + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + + case SCAN_ID: + if(!sector_matches()) { + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + } + if(cur_live.crc) { + fprintf(stderr, "Header CRC error\n"); + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; + } + sector_size = calc_sector_size(cur_live.idbuf[3]); + fifo_expect(sector_size, true); + fi.sub_state = SECTOR_WRITTEN; + live_start(fi, WRITE_SECTOR_SKIP_GAP2); + return; + + case SCAN_ID_FAILED: + st0 |= ST0_FAIL; + st1 |= ST1_ND; + fi.sub_state = COMMAND_DONE; + break; -READ8_DEVICE_HANDLER(upd765_data_r) -{ - upd765_t *fdc = get_safe_token(device); - -// if ((fdc->FDC_main & 0x0c0) == 0x0c0) - if ((fdc->FDC_main & 0x080) == 0x080) - { - if ( - (fdc->upd765_phase == UPD765_EXECUTION_PHASE_READ) || - (fdc->upd765_phase == UPD765_EXECUTION_PHASE_WRITE)) - { - - /* reading the data byte clears the interrupt */ - upd765_set_int(device,CLEAR_LINE); + case SECTOR_WRITTEN: { + bool done = tc_done; + command[4]++; + if(command[4] > command[6]) { + command[4] = 1; + if(command[0] & 0x80) { + command[3] = command[3] ^ 1; + if(fi.dev) + fi.dev->ss_w(command[3] & 1); + } + if(!(command[0] & 0x80) || !(command[3] & 1)) { + command[2]++; + if(!tc_done) { + st0 |= ST0_FAIL; + st1 |= ST1_EN; + } + done = true; + } + } + if(!done) { + fi.sub_state = HEAD_LOAD_DONE; + break; + } + fi.sub_state = COMMAND_DONE; + break; } - /* reset data request */ - upd765_clear_data_request(device); + case COMMAND_DONE: + main_phase = PHASE_RESULT; + result[0] = st0; + result[1] = st1; + result[2] = st2; + result[3] = command[2]; + result[4] = command[3]; + result[5] = command[4]; + result[6] = command[5]; + result_pos = 7; + command_end(fi, true); + return; - /* update state */ - upd765_update_state(device); + default: + logerror("%s: write sector unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + return; + } } - - if (LOG_EXTRA) - logerror("DATA R: %02x\n", fdc->upd765_data_reg); - - return fdc->upd765_data_reg; } -WRITE8_DEVICE_HANDLER(upd765_data_w) +void upd765_family_device::read_track_start(floppy_info &fi) { - upd765_t *fdc = get_safe_token(device); - - if (LOG_EXTRA) - logerror("DATA W: %02x\n", data); + fi.main_state = READ_TRACK; + fi.sub_state = HEAD_LOAD_DONE; - /* write data to data reg */ - fdc->upd765_data_reg = data; + logerror("%s: command read track%s cmd=%02x sel=%x chrn=(%d, %d, %d, %d) eot=%02x gpl=%02x dtl=%02x rate=%d\n", + tag(), + command[0] & 0x40 ? " mfm" : "", + command[0], + command[1], + command[2], + command[3], + command[4], + 128 << (command[5] & 7), + command[6], + command[7], + command[8], + cur_rate); - if ((fdc->FDC_main & 0x0c0)==0x080) - { - if ( - (fdc->upd765_phase == UPD765_EXECUTION_PHASE_READ) || - (fdc->upd765_phase == UPD765_EXECUTION_PHASE_WRITE)) - { - - /* reading the data byte clears the interrupt */ - upd765_set_int(device, CLEAR_LINE); - } - - /* reset data request */ - upd765_clear_data_request(device); - - /* update state */ - upd765_update_state(device); - } + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + read_track_continue(fi); } -static void upd765_setup_invalid(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); - - fdc->command = 0; - fdc->upd765_result_bytes[0] = 0x080; - upd765_setup_result_phase(device,1); -} - -static void upd765_setup_command(device_t *device) -{ - upd765_t *fdc = get_safe_token(device); - - static const char *const commands[] = - { - NULL, /* [00] */ - NULL, /* [01] */ - "Read Track", /* [02] */ - "Specify", /* [03] */ - "Sense Drive Status", /* [04] */ - "Write Data", /* [05] */ - "Read Data", /* [06] */ - "Recalibrate", /* [07] */ - "Sense Interrupt Status", /* [08] */ - "Write Deleted Data", /* [09] */ - "Read ID", /* [0A] */ - NULL, /* [0B] */ - "Read Deleted Data", /* [0C] */ - "Format Track", /* [0D] */ - "Dump Registers", /* [0E] */ - "Seek", /* [0F] */ - "Version", /* [10] */ - NULL, /* [11] */ - "Perpendicular Mode", /* [12] */ - "Configure", /* [13] */ - "Lock" /* [14] */ - }; - - device_t *img; - const char *cmd = NULL; - chrn_id id; - - /* if not in dma mode set execution phase bit */ - if (!(fdc->upd765_flags & UPD765_DMA_MODE)) - { - fdc->FDC_main |= 0x020; /* execution phase */ - } - - if (LOG_COMMAND) - { - if ((fdc->upd765_command_bytes[0] & 0x1f) < ARRAY_LENGTH(commands)) - cmd = commands[fdc->upd765_command_bytes[0] & 0x1f]; - logerror("upd765_setup_command(): Setting up command 0x%02X (%s)\n", - fdc->upd765_command_bytes[0] & 0x1f, cmd ? cmd : "???"); - } - - switch (fdc->upd765_command_bytes[0] & 0x1f) - { - case 0x03: /* specify */ - /* setup step rate */ - fdc->srt_in_ms = 16-((fdc->upd765_command_bytes[1]>>4) & 0x0f); - - fdc->upd765_flags &= ~UPD765_DMA_MODE; - - if ((fdc->upd765_command_bytes[2] & 0x01)==0) - { - fdc->upd765_flags |= UPD765_DMA_MODE; +void upd765_family_device::read_track_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + if(fi.pcn == command[2] || !(fifocfg & 0x40)) { + fi.sub_state = SEEK_DONE; + break; } - - upd765_idle(device); - break; - - case 0x04: /* sense drive status */ - upd765_setup_drive_and_side(device); - img = current_image(device); - - fdc->upd765_status[3] = fdc->drive | (fdc->side<<2); - - if (img) - { - fdc->upd765_status[3] |= !floppy_tk00_r(img) << 4; - fdc->upd765_status[3] |= !floppy_wpt_r(img) << 6; - - if (upd765_get_rdy(device)) - { - fdc->upd765_status[3] |= 0x20; - } + if(fi.dev) { + fi.dev->dir_w(fi.pcn > command[2] ? 1 : 0); + fi.dev->stp_w(0); } + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME; + fi.tm->adjust(attotime::from_nsec(2500)); + return; - fdc->upd765_status[3] |= 0x08; - - /* two side and fault not set but should be? */ - fdc->upd765_result_bytes[0] = fdc->upd765_status[3]; - upd765_setup_result_phase(device,1); - break; - - case 0x07: /* recalibrate */ - upd765_seek_setup(device, 1); - break; - - case 0x0f: /* seek */ - upd765_seek_setup(device, 0); - break; + case SEEK_WAIT_STEP_SIGNAL_TIME: + return; - case 0x0a: /* read id */ - upd765_setup_drive_and_side(device); - img = current_image(device); - - fdc->upd765_status[0] = fdc->drive | (fdc->side<<2); - fdc->upd765_status[1] = 0; - fdc->upd765_status[2] = 0; - - /* drive ready? */ - if (upd765_get_rdy(device)) - { - /* is disk inserted? */ - device_image_interface *image = dynamic_cast<device_image_interface *>( img); - if (image!=NULL && image->exists()) - { - int index_count = 0; - - /* floppy drive is ready and disc is inserted */ - - /* this is the id that appears when a disc is not formatted */ - /* to be checked on Amstrad */ - id.C = 0; - id.H = 0; - id.R = 0x01; - id.N = 0x02; - - /* repeat for two index counts before quitting */ - do - { - /* get next id from disc */ - if (floppy_drive_get_next_id(img, fdc->side, &id)) - { - /* got an id */ - /* if bad media keep going until failure */ - if (!(fdc->upd765_flags & UPD765_BAD_MEDIA)) break; - } - - if (floppy_drive_get_flag_state(img, FLOPPY_DRIVE_INDEX)) - { - /* update index count */ - index_count++; - } - } - while (index_count!=2); + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + if(fi.dev) + fi.dev->stp_w(1); - if (fdc->upd765_flags & UPD765_BAD_MEDIA) - { - fdc->upd765_status[0] |= 0x40; - fdc->upd765_status[1] |= 1; - } + fi.sub_state = SEEK_WAIT_STEP_TIME; + delay_cycles(fi.tm, 500*(16-(spec >> 12))); + return; - /* at this point, we have seen a id or two index pulses have occurred! */ - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - fdc->upd765_result_bytes[1] = fdc->upd765_status[1]; - fdc->upd765_result_bytes[2] = fdc->upd765_status[2]; - fdc->upd765_result_bytes[3] = id.C; /* C */ - fdc->upd765_result_bytes[4] = id.H; /* H */ - fdc->upd765_result_bytes[5] = id.R; /* R */ - fdc->upd765_result_bytes[6] = id.N; /* N */ + case SEEK_WAIT_STEP_TIME: + return; - upd765_setup_result_phase(device,7); - } - else - { - /* floppy drive is ready, but no disc is inserted */ - /* this occurs on the PC */ - /* in this case, the command never quits! */ - /* there are no index pulses to stop the command! */ - } - } + case SEEK_WAIT_STEP_TIME_DONE: + if(fi.pcn > command[2]) + fi.pcn--; else - { - /* what are id values when drive not ready? */ - - /* not ready, abnormal termination */ - fdc->upd765_status[0] |= (1<<3) | (1<<6); - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - fdc->upd765_result_bytes[1] = fdc->upd765_status[1]; - fdc->upd765_result_bytes[2] = fdc->upd765_status[2]; - fdc->upd765_result_bytes[3] = 0; /* C */ - fdc->upd765_result_bytes[4] = 0; /* H */ - fdc->upd765_result_bytes[5] = 0; /* R */ - fdc->upd765_result_bytes[6] = 0; /* N */ - } + fi.pcn++; + fi.sub_state = HEAD_LOAD_DONE; break; + case SEEK_DONE: + fi.counter = 0; + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; - case 0x08: /* sense interrupt status */ - /* interrupt pending? */ - if (fdc->upd765_flags & UPD765_INT) - { - /* clear ready changed bit */ - fdc->ready_changed &= ~(1 << fdc->drive); - - if (!fdc->pool) { - fdc->ready_changed = 0; - } - - /* clear drive seek bits */ - fdc->FDC_main &= ~(1 | 2 | 4 | 8); - - /* return status */ - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - /* return pcn */ - fdc->upd765_result_bytes[1] = fdc->pcn[fdc->drive]; - - /* return result */ - upd765_setup_result_phase(device,2); - - if (fdc->ready_changed) - { - fdc->drive++; - fdc->upd765_status[0] = 0xc0 | fdc->drive; - } - else - { - /* Clear int */ - upd765_set_int(device, CLEAR_LINE); - } + case SCAN_ID: + if(cur_live.crc) { + fprintf(stderr, "Header CRC error\n"); + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; } - else - { - if(fdc->version == TYPE_UPD72065 && (fdc->FDC_main & 0x0f) == 0x00) - { // based on XM6 - upd765_setup_invalid(device); - } - else - { - /* no int */ - fdc->upd765_result_bytes[0] = 0x80; - /* return pcn */ - fdc->upd765_result_bytes[1] = fdc->pcn[fdc->drive]; - - /* return result */ - upd765_setup_result_phase(device,2); - } + sector_size = calc_sector_size(cur_live.idbuf[3]); + fifo_expect(sector_size, false); + fi.sub_state = SECTOR_READ; + live_start(fi, SEARCH_ADDRESS_MARK_DATA); + return; + + case SCAN_ID_FAILED: + fprintf(stderr, "RNF\n"); + // command_end(fi, true, 1); + return; + + case SECTOR_READ: + if(cur_live.crc) { + fprintf(stderr, "CRC error\n"); + } + if(command[4] < command[6]) { + command[4]++; + fi.sub_state = HEAD_LOAD_DONE; + break; } - break; - - case 0x06: /* read data */ - upd765_setup_drive_and_side(device); - fdc->upd765_status[0] = fdc->drive | (fdc->side<<2); - fdc->upd765_status[1] = 0; - fdc->upd765_status[2] = 0; + main_phase = PHASE_RESULT; + result[0] = 0x40 | (fi.dev->ss_r() << 2) | fi.id; + result[1] = 0; + result[2] = 0; + result[3] = command[2]; + result[4] = command[3]; + result[5] = command[4]; + result[6] = command[5]; + result_pos = 7; + // command_end(fi, true, 0); + return; - upd765_read_data(device); - break; + default: + logerror("%s: read track unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + return; + } + } +} - case 0x0c: - /* read deleted data */ - upd765_setup_drive_and_side(device); +int upd765_family_device::calc_sector_size(UINT8 size) +{ + return size > 7 ? 16384 : 128 << size; +} - fdc->upd765_status[0] = fdc->drive | (fdc->side<<2); - fdc->upd765_status[1] = 0; - fdc->upd765_status[2] = 0; +void upd765_family_device::format_track_start(floppy_info &fi) +{ + fi.main_state = FORMAT_TRACK; + fi.sub_state = HEAD_LOAD_DONE; - /* .. for now */ - upd765_read_data(device); - break; + logerror("%s: command format track %s h=%02x n=%02x sc=%02x gpl=%02x d=%02x\n", + tag(), + command[0] & 0x40 ? "mfm" : "fm", + command[1], command[2], command[3], command[4], command[5]); - case 0x09: - /* write deleted data */ - upd765_setup_drive_and_side(device); + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); + sector_size = calc_sector_size(command[2]); - fdc->upd765_status[0] = fdc->drive | (fdc->side<<2); - fdc->upd765_status[1] = 0; - fdc->upd765_status[2] = 0; + format_track_continue(fi); +} - /* ... for now */ - upd765_write_data(device); +void upd765_family_device::format_track_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + fi.sub_state = WAIT_INDEX; break; - case 0x02: - /* read a track */ - upd765_setup_drive_and_side(device); - img = current_image(device); - fdc->upd765_status[0] = fdc->drive | (fdc->side<<2); - fdc->upd765_status[1] = 0; - fdc->upd765_status[2] = 0; - - fdc->upd765_status[0] |= UPD765_ST1_NO_DATA; - - /* wait for index */ - do - { - /* get next id from disc */ - floppy_drive_get_next_id(img, fdc->side,&id); - } - while ((floppy_drive_get_flag_state(img, FLOPPY_DRIVE_INDEX))==0); + case WAIT_INDEX: + return; + + case WAIT_INDEX_DONE: + logerror("%s: index found, writing track\n", tag()); + fi.sub_state = TRACK_DONE; + cur_live.pll.start_writing(machine().time()); + live_start(fi, WRITE_TRACK_PRE_SECTORS); + return; + + case TRACK_DONE: + main_phase = PHASE_RESULT; + result[0] = (fi.dev->ss_r() << 2) | fi.id; + result[1] = 0; + result[2] = 0; + result[3] = 0; + result[4] = 0; + result[5] = 0; + result[6] = 0; + result_pos = 7; + command_end(fi, true); + return; - fdc->sector_counter = 0; + default: + logerror("%s: format track unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + return; + } + } +} - upd765_read_a_track(device); - break; +void upd765_family_device::read_id_start(floppy_info &fi) +{ + fi.main_state = READ_ID; + fi.sub_state = HEAD_LOAD_DONE; - case 0x05: /* write data */ - upd765_setup_drive_and_side(device); + logerror("%s: command read id%s, rate=%d\n", + tag(), + command[0] & 0x40 ? " mfm" : "", + cur_rate); - fdc->upd765_status[0] = fdc->drive | (fdc->side<<2); - fdc->upd765_status[1] = 0; - fdc->upd765_status[2] = 0; + if(fi.dev) + fi.dev->ss_w(command[1] & 4 ? 1 : 0); - upd765_write_data(device); - break; + st0 = command[1] & 7; + st1 = 0x00; + st2 = 0x00; - case 0x0d: /* format a track */ - upd765_setup_drive_and_side(device); + for(int i=0; i<4; i++) + cur_live.idbuf[i] = 0x00; - fdc->upd765_status[0] = fdc->drive | (fdc->side<<2); - fdc->upd765_status[1] = 0; - fdc->upd765_status[2] = 0; + read_id_continue(fi); +} - fdc->sector_counter = 0; +void upd765_family_device::read_id_continue(floppy_info &fi) +{ + for(;;) { + switch(fi.sub_state) { + case HEAD_LOAD_DONE: + fi.counter = 0; + fi.sub_state = SCAN_ID; + live_start(fi, SEARCH_ADDRESS_MARK_HEADER); + return; - upd765_format_track(device); + case SCAN_ID: + if(cur_live.crc) { + st0 |= ST0_FAIL; + st1 |= ST1_MA|ST1_DE|ST1_ND; + } + fi.sub_state = COMMAND_DONE; break; - default: /* invalid */ - switch (fdc->version) - { - case TYPE_UPD765A: - upd765_setup_invalid(device); - break; + case SCAN_ID_FAILED: + st0 |= ST0_FAIL; + st1 |= ST1_ND|ST1_MA; + fi.sub_state = COMMAND_DONE; + break; - case TYPE_UPD765B: - /* from upd765b data sheet */ - if ((fdc->upd765_command_bytes[0] & 0x01f)==0x010) - { - /* version */ - fdc->upd765_status[0] = 0x090; - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - upd765_setup_result_phase(device,1); - } - break; + case COMMAND_DONE: + main_phase = PHASE_RESULT; + result[0] = st0; + result[1] = st1; + result[2] = st2; + result[3] = cur_live.idbuf[0]; + result[4] = cur_live.idbuf[1]; + result[5] = cur_live.idbuf[2]; + result[6] = cur_live.idbuf[3]; + result_pos = 7; + command_end(fi, true); + return; - case TYPE_UPD72065: - switch(fdc->upd765_command_bytes[0] & 0x3f) - { - case 0x36: // Software Reset - upd765_reset(device,0); - upd765_idle(device); - if(LOG_COMMAND) - logerror("upd72065: command - Software Reset\n"); - break; - default: - upd765_setup_invalid(device); - break; - } - break; - - case TYPE_SMC37C78: - /* TO BE COMPLETED!!! !*/ - switch (fdc->upd765_command_bytes[0] & 0x1f) - { - case 0x10: /* version */ - fdc->upd765_status[0] = 0x90; - fdc->upd765_result_bytes[0] = fdc->upd765_status[0]; - upd765_setup_result_phase(device,1); - break; - - case 0x13: /* configure */ - fdc->pool = fdc->upd765_command_bytes[1] & 0x10; - upd765_idle(device); - break; - - case 0x0e: /* dump reg */ - fdc->upd765_result_bytes[0] = fdc->pcn[0]; - fdc->upd765_result_bytes[1] = fdc->pcn[1]; - fdc->upd765_result_bytes[2] = fdc->pcn[2]; - fdc->upd765_result_bytes[3] = fdc->pcn[3]; - - upd765_setup_result_phase(device,10); - break; - - case 0x12: /* perpendicular mode */ - upd765_idle(device); - break; - - case 0x14: /* lock */ - upd765_setup_result_phase(device,1); - break; - } - break; - } + default: + logerror("%s: read id unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + return; + } } } - -/* dma acknowledge write */ -WRITE8_DEVICE_HANDLER(upd765_dack_w) +void upd765_family_device::check_irq() { - /* clear request */ - upd765_set_dma_drq(device, CLEAR_LINE); - - /* write data */ - upd765_data_w(device, space, offset, data); + bool old_irq = cur_irq; + cur_irq = data_irq || internal_drq; + for(int i=0; i<4; i++) + cur_irq = cur_irq || flopi[i].irq_seek || flopi[i].irq_polled; + cur_irq = cur_irq && (dor & 4) && (dor & 8); + if(cur_irq != old_irq && !intrq_cb.isnull()) { + logerror("%s: irq = %d\n", tag(), cur_irq); + intrq_cb(cur_irq); + } } -READ8_DEVICE_HANDLER(upd765_dack_r) +bool upd765_family_device::get_irq() const { - /* clear data request */ - upd765_set_dma_drq(device,CLEAR_LINE); - - /* read data */ - return upd765_data_r(device, space, offset); + return cur_irq; } -static TIMER_CALLBACK( interrupt_callback ) +astring upd765_family_device::tts(attotime t) { - device_t* device = (device_t*)ptr; - upd765_set_int(device, 1); + char buf[256]; + const char *sign = ""; + if(t.seconds < 0) { + t = attotime::zero-t; + sign = "-"; + } + int nsec = t.attoseconds / ATTOSECONDS_PER_NANOSECOND; + sprintf(buf, "%s%04d.%03d,%03d,%03d", sign, int(t.seconds), nsec/1000000, (nsec/1000)%1000, nsec % 1000); + return buf; } -void upd765_set_bad(device_t *device, int state) +astring upd765_family_device::ttsn() { - upd765_t *fdc = get_safe_token(device); - if (state) fdc->upd765_flags |= UPD765_BAD_MEDIA; - else fdc->upd765_flags &= ~UPD765_BAD_MEDIA; + return tts(machine().time()); } -void upd765_reset(device_t *device, int offset) +void upd765_family_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { - upd765_t *fdc = get_safe_token(device); + if(id == TIMER_DRIVE_READY_POLLING) { + run_drive_ready_polling(); + return; + } - /* upd765 in idle state - ready to accept commands */ - upd765_idle(device); + live_sync(); + + floppy_info &fi = flopi[id]; + switch(fi.sub_state) { + case SEEK_WAIT_STEP_SIGNAL_TIME: + fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME_DONE; + break; + case SEEK_WAIT_STEP_TIME: + fi.sub_state = SEEK_WAIT_STEP_TIME_DONE; + break; + } - /* set int low */ - upd765_set_int(device, 0); - /* set dma drq output */ - upd765_set_dma_drq(device,0); + general_continue(fi); +} - /* tandy 100hx assumes that after NEC is reset, it is in DMA mode */ - fdc->upd765_flags |= UPD765_DMA_MODE; +void upd765_family_device::run_drive_ready_polling() +{ + if(main_phase != PHASE_CMD || (fifocfg & FIF_POLL)) + return; - /* if ready input is set during reset generate an int */ - if (upd765_get_rdy(device)) - { - int i; - int a_drive_is_ready; + bool changed = false; + for(int fid=0; fid<4; fid++) { + bool ready = get_ready(fid); + if(ready != flopi[fid].ready) { + logerror("%s: polled %d : %d -> %d\n", tag(), fid, flopi[fid].ready, ready); + flopi[fid].ready = ready; + flopi[fid].irq_polled = true; + changed = true; + } + } + if(changed) + check_irq(); +} - fdc->upd765_status[0] = 0x080 | 0x040; +void upd765_family_device::index_callback(floppy_image_device *floppy, int state) +{ + for(int fid=0; fid<4; fid++) { + floppy_info &fi = flopi[fid]; + if(fi.dev != floppy) + continue; - // HACK signal ready changed for all drives - fdc->ready_changed = 0x0f; - fdc->drive = 0; + if(fi.live) + live_sync(); + fi.index = state; - /* for the purpose of pc-xt. If any of the drives have a disk inserted, - do not set not-ready - need to check with pc_fdc.c whether all drives - are checked or only the drive selected with the drive select bits?? */ + if(!state) { + general_continue(fi); + continue; + } - a_drive_is_ready = 0; - for (i = 0; i < 4; i++) - { - if (fdc->intf->floppy_drive_tags[i]!=NULL) - { - device_t *img; + switch(fi.sub_state) { + case IDLE: + case SEEK_MOVE: + case SEEK_WAIT_STEP_SIGNAL_TIME: + case SEEK_WAIT_STEP_SIGNAL_TIME_DONE: + case SEEK_WAIT_STEP_TIME: + case SEEK_WAIT_STEP_TIME_DONE: + case HEAD_LOAD_DONE: + case SCAN_ID_FAILED: + case SECTOR_READ: + break; - if (device->owner() != NULL) - img = device->owner()->subdevice(fdc->intf->floppy_drive_tags[i]); - else - img = device->machine().device(fdc->intf->floppy_drive_tags[i]); + case WAIT_INDEX: + fi.sub_state = WAIT_INDEX_DONE; + break; - device_image_interface *image = dynamic_cast<device_image_interface *>( img); - if (image->exists()) - { - a_drive_is_ready = 1; - break; - } + case SCAN_ID: + fi.counter++; + if(fi.counter == 2) { + fi.sub_state = SCAN_ID_FAILED; + live_abort(); } + break; - } + case TRACK_DONE: + live_abort(); + break; - if (!a_drive_is_ready && fdc->intf->rdy_pin == UPD765_RDY_PIN_CONNECTED ) - { - fdc->upd765_status[0] |= 0x08; + default: + logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().cstr(), fi.sub_state); + break; } - device->machine().scheduler().timer_set(attotime::from_usec(5), FUNC(interrupt_callback),0,device); + general_continue(fi); } } -WRITE_LINE_DEVICE_HANDLER( upd765_reset_w ) + +void upd765_family_device::general_continue(floppy_info &fi) { - upd765_t *fdc = get_safe_token(device); + if(fi.live && cur_live.state != IDLE) { + live_run(); + if(cur_live.state != IDLE) + return; + } - int flags; + switch(fi.main_state) { + case IDLE: + break; - /* get previous reset state */ - flags = fdc->upd765_flags; + case RECALIBRATE: + case SEEK: + seek_continue(fi); + break; - /* set new reset state */ - /* clear reset */ - fdc->upd765_flags &= ~UPD765_RESET; + case READ_DATA: + read_data_continue(fi); + break; - /* reset */ - if (state) - { - fdc->upd765_flags |= UPD765_RESET; + case WRITE_DATA: + write_data_continue(fi); + break; - upd765_set_int(device, 0); - } + case READ_TRACK: + read_track_continue(fi); + break; - /* reset changed state? */ - if (((flags^fdc->upd765_flags) & UPD765_RESET)!=0) - { - /* yes */ + case FORMAT_TRACK: + format_track_continue(fi); + break; - /* no longer reset */ - if ((fdc->upd765_flags & UPD765_RESET)==0) - { - /* reset nec */ - upd765_reset(device, 0); - } + case READ_ID: + read_id_continue(fi); + break; + + default: + logerror("%s: general_continue on unknown main-state %d\n", ttsn().cstr(), fi.main_state); + break; } } - -WRITE_LINE_DEVICE_HANDLER( upd765_ready_w ) +bool upd765_family_device::read_one_bit(attotime limit) { - upd765_t *fdc = get_safe_token(device); - - /* clear ready state */ - fdc->upd765_flags &= ~UPD765_FDD_READY; - - if (state) - { - fdc->upd765_flags |= UPD765_FDD_READY; + int bit = cur_live.pll.get_next_bit(cur_live.tm, cur_live.fi->dev, limit); + if(bit < 0) + return true; + cur_live.shift_reg = (cur_live.shift_reg << 1) | bit; + cur_live.bit_counter++; + if(cur_live.data_separator_phase) { + cur_live.data_reg = (cur_live.data_reg << 1) | bit; + if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + cur_live.crc = (cur_live.crc << 1) ^ 0x1021; + else + cur_live.crc = cur_live.crc << 1; } + cur_live.data_separator_phase = !cur_live.data_separator_phase; + return false; } - -/* Device Interface */ - -static void common_start(device_t *device, int device_type) +bool upd765_family_device::write_one_bit(attotime limit) { - upd765_t *fdc = get_safe_token(device); - // validate arguments - - assert(device != NULL); - assert(device->tag() != NULL); - assert(device->static_config() != NULL); - - fdc->intf = (const upd765_interface*)device->static_config(); + bool bit = cur_live.shift_reg & 0x8000; + if(cur_live.pll.write_next_bit(bit, cur_live.tm, cur_live.fi->dev, limit)) + return true; + if(cur_live.bit_counter & 1) { + if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000) + cur_live.crc = (cur_live.crc << 1) ^ 0x1021; + else + cur_live.crc = cur_live.crc << 1; + } + cur_live.shift_reg = cur_live.shift_reg << 1; + cur_live.bit_counter--; + return false; +} - fdc->version = (UPD765_VERSION)device_type; - fdc->timer = device->machine().scheduler().timer_alloc(FUNC(upd765_timer_callback), (void*)device); - fdc->seek_timer = device->machine().scheduler().timer_alloc(FUNC(upd765_seek_timer_callback), (void*)device); - fdc->command_timer = device->machine().scheduler().timer_alloc(FUNC(upd765_continue_command), (void*)device); +void upd765_family_device::live_write_raw(UINT16 raw) +{ + // logerror("write %04x %04x\n", raw, cur_live.crc); + cur_live.shift_reg = raw; + cur_live.data_bit_context = raw & 1; +} - fdc->upd765_flags &= UPD765_FDD_READY; - fdc->data_buffer = auto_alloc_array(device->machine(), char, 32*1024); +void upd765_family_device::live_write_mfm(UINT8 mfm) +{ + bool context = cur_live.data_bit_context; + UINT16 raw = 0; + for(int i=0; i<8; i++) { + bool bit = mfm & (0x80 >> i); + if(!(bit || context)) + raw |= 0x8000 >> (2*i); + if(bit) + raw |= 0x4000 >> (2*i); + context = bit; + } + cur_live.data_reg = mfm; + cur_live.shift_reg = raw; + cur_live.data_bit_context = context; + // logerror("write %02x %04x %04x\n", mfm, cur_live.crc, raw); +} - fdc->out_int_func.resolve(fdc->intf->out_int_func, *device); - fdc->out_drq_func.resolve(fdc->intf->out_drq_func, *device); +bool upd765_family_device::sector_matches() const +{ + return + cur_live.idbuf[0] == command[2] && + cur_live.idbuf[1] == command[3] && + cur_live.idbuf[2] == command[4] && + cur_live.idbuf[3] == command[5]; +} - // plain upd765 is doing pooling - fdc->pool = true; - // register for state saving - //state_save_register_item(device->machine(), "upd765", device->tag(), 0, upd765->number); +void upd765_family_device::pll_t::set_clock(attotime _period) +{ + period = _period; + period_adjust_base = period * 0.05; + min_period = period * 0.75; + max_period = period * 1.25; } -static DEVICE_START( upd765a ) +void upd765_family_device::pll_t::reset(attotime when) { - common_start(device, TYPE_UPD765A); + ctime = when; + phase_adjust = attotime::zero; + freq_hist = 0; + write_position = 0; + write_start_time = attotime::never; } -static DEVICE_START( upd765b ) +void upd765_family_device::pll_t::start_writing(attotime tm) { - common_start(device, TYPE_UPD765B); + write_start_time = tm; + write_position = 0; } -static DEVICE_START( smc37c78 ) +void upd765_family_device::pll_t::stop_writing(floppy_image_device *floppy, attotime tm) { - common_start(device, TYPE_SMC37C78); - // specified in documentation that by default is off - upd765_t *fdc = get_safe_token(device); - fdc->pool = false; + commit(floppy, tm); + write_start_time = attotime::never; } -static DEVICE_START( upd72065 ) +void upd765_family_device::pll_t::commit(floppy_image_device *floppy, attotime tm) { - common_start(device, TYPE_UPD72065); + if(write_start_time.is_never() || tm == write_start_time) + return; + + if(floppy) + floppy->write_flux(write_start_time, tm, write_position, write_buffer); + write_start_time = tm; + write_position = 0; } -static DEVICE_RESET( upd765 ) +int upd765_family_device::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit) { - int i; - upd765_t *fdc = get_safe_token(device); - for (i = 0; i < 4; i++) { - if (fdc->intf->floppy_drive_tags[i]!=NULL) - { - device_t *img; + attotime edge = floppy ? floppy->get_next_transition(ctime) : attotime::never; - if (device->owner() != NULL) - img = device->owner()->subdevice(fdc->intf->floppy_drive_tags[i]); - else - img = device->machine().device(fdc->intf->floppy_drive_tags[i]); + attotime next = ctime + period + phase_adjust; - floppy_drive_set_controller(img, device); - floppy_drive_set_ready_state_change_callback(img, upd765_set_ready_change_callback); - } - } +#if 0 + if(!edge.is_never()) + fprintf(stderr, "ctime=%s, transition_time=%s, next=%s, pha=%s\n", tts(ctime).cstr(), tts(edge).cstr(), tts(next).cstr(), tts(phase_adjust).cstr()); +#endif - upd765_reset(device,0); -} + if(next > limit) + return -1; -const device_type UPD765A = &device_creator<upd765a_device>; + ctime = next; -upd765a_device::upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, UPD765A, "UPD765A", tag, owner, clock) -{ - m_token = global_alloc_clear(upd765_t); -} -upd765a_device::upd765a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, type, name, tag, owner, clock) -{ - m_token = global_alloc_clear(upd765_t); -} + if(edge.is_never() || edge >= next) { + // No transition in the window means 0 and pll in free run mode + phase_adjust = attotime::zero; + tm = next; + return 0; + } -//------------------------------------------------- -// device_config_complete - perform any -// operations now that the configuration is -// complete -//------------------------------------------------- + // Transition in the window means 1, and the pll is adjusted -void upd765a_device::device_config_complete() -{ -} + attotime delta = edge - (next - period/2); -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- + if(delta.seconds < 0) + phase_adjust = attotime::zero - ((attotime::zero - delta)*65)/100; + else + phase_adjust = (delta*65)/100; -void upd765a_device::device_start() -{ - DEVICE_START_NAME( upd765a )(this); -} + if(delta < attotime::zero) { + if(freq_hist < 0) + freq_hist--; + else + freq_hist = -1; + } else if(delta > attotime::zero) { + if(freq_hist > 0) + freq_hist++; + else + freq_hist = 1; + } else + freq_hist = 0; + + if(freq_hist) { + int afh = freq_hist < 0 ? -freq_hist : freq_hist; + if(afh > 1) { + attotime aper = attotime::from_double(period_adjust_base.as_double()*delta.as_double()/period.as_double()); + period += aper; + + if(period < min_period) + period = min_period; + else if(period > max_period) + period = max_period; + } + } -//------------------------------------------------- -// device_reset - device-specific reset -//------------------------------------------------- + return 1; +} -void upd765a_device::device_reset() +bool upd765_family_device::pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit) { - DEVICE_RESET_NAME( upd765 )(this); -} + if(write_start_time.is_never()) { + write_start_time = ctime; + write_position = 0; + } + attotime etime = ctime + period; + if(etime > limit) + return true; -const device_type UPD765B = &device_creator<upd765b_device>; + if(bit && write_position < ARRAY_LENGTH(write_buffer)) + write_buffer[write_position++] = ctime + period/2; -upd765b_device::upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : upd765a_device(mconfig, UPD765B, "UPD765B", tag, owner, clock) -{ + tm = etime; + ctime = etime; + return false; } -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void upd765b_device::device_start() +upd765a_device::upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD765A, "UPD765A", tag, owner, clock) { - DEVICE_START_NAME( upd765b )(this); + m_shortname = "upd765a"; + dor_reset = 0x0c; } - -const device_type SMC37C78 = &device_creator<smc37c78_device>; - -smc37c78_device::smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : upd765a_device(mconfig, SMC37C78, "SMC37C78", tag, owner, clock) +upd765b_device::upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD765B, "UPD765B", tag, owner, clock) { + m_shortname = "upd765b"; + dor_reset = 0x0c; } -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void smc37c78_device::device_start() +i8272a_device::i8272a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, I8272A, "I8272A", tag, owner, clock) { - DEVICE_START_NAME( smc37c78 )(this); + m_shortname = "i8272a"; + dor_reset = 0x0c; } - -const device_type UPD72065 = &device_creator<upd72065_device>; - -upd72065_device::upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : upd765a_device(mconfig, UPD72065, "UPD72065", tag, owner, clock) +upd72065_device::upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, UPD72065, "UPD72065", tag, owner, clock) { + m_shortname = "upd72065"; + dor_reset = 0x0c; } -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void upd72065_device::device_start() +smc37c78_device::smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, SMC37C78, "SMC37C78", tag, owner, clock) { - DEVICE_START_NAME( upd72065 )(this); + m_shortname = "smc37c78"; + ready_connected = false; + select_connected = true; } +n82077aa_device::n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, N82077AA, "N82077AA", tag, owner, clock) +{ + m_shortname = "n82077aa"; + ready_connected = false; + select_connected = true; +} +pc_fdc_superio_device::pc_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : upd765_family_device(mconfig, PC_FDC_SUPERIO, "PC FDC SUPERIO", tag, owner, clock) +{ + m_shortname = "pc_fdc_superio"; + ready_polled = false; + ready_connected = false; + select_connected = true; +} diff --git a/src/mess/machine/upd765.h b/src/mess/machine/upd765.h index cac6bee3649..f7fd07b5506 100644 --- a/src/mess/machine/upd765.h +++ b/src/mess/machine/upd765.h @@ -1,215 +1,434 @@ -/*************************************************************************** +#ifndef __UPD765_F_H__ +#define __UPD765_F_H__ - machine/upd765.h +#include "emu.h" +#include "imagedev/floppy.h" - Functions to emulate a NEC upd765/Intel 8272 compatible - floppy disk controller +/* + * ready = true if the ready line is physically connected to the floppy drive + * select = true if the fdc controls the floppy drive selection + * mode = MODE_AT, MODE_PS2 or MODE_M30 for the fdcs that have reset-time selection + */ -***************************************************************************/ +#define MCFG_UPD765A_ADD(_tag, _ready, _select) \ + MCFG_DEVICE_ADD(_tag, UPD765A, 0) \ + downcast<upd765a_device *>(device)->set_ready_line_connected(_ready); \ + downcast<upd765a_device *>(device)->set_select_lines_connected(_select); -#ifndef __UPD765_H__ -#define __UPD765_H__ +#define MCFG_UPD765B_ADD(_tag, _ready, _select) \ + MCFG_DEVICE_ADD(_tag, UPD765B, 0) \ + downcast<upd765b_device *>(device)->set_ready_line_connected(_ready); \ + downcast<upd765b_device *>(device)->set_select_lines_connected(_select); -#include "devcb.h" -#include "imagedev/flopdrv.h" +#define MCFG_I8272A_ADD(_tag, _ready) \ + MCFG_DEVICE_ADD(_tag, I8272A, 0) \ + downcast<i8272a_device *>(device)->set_ready_line_connected(_ready); +#define MCFG_UPD72065_ADD(_tag, _ready, _select) \ + MCFG_DEVICE_ADD(_tag, UPD72065, 0) \ + downcast<upd72065_device *>(device)->set_ready_line_connected(_ready); \ + downcast<upd72065_device *>(device)->set_select_lines_connected(_select); -/*************************************************************************** - MACROS -***************************************************************************/ +#define MCFG_SMC37C78_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, SMC37C78, 0) -class upd765a_device : public device_t -{ -public: - upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - upd765a_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); - ~upd765a_device() { global_free(m_token); } - - // access to legacy token - void *token() const { assert(m_token != NULL); return m_token; } -protected: - // device-level overrides - virtual void device_config_complete(); - virtual void device_start(); - virtual void device_reset(); -private: - // internal state - void *m_token; -}; - -extern const device_type UPD765A; - -class upd765b_device : public upd765a_device -{ -public: - upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); -protected: - // device-level overrides - virtual void device_start(); -}; - -extern const device_type UPD765B; - -class smc37c78_device : public upd765a_device -{ -public: - smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); -protected: - // device-level overrides - virtual void device_start(); -}; +#define MCFG_N82077AA_ADD(_tag, _mode) \ + MCFG_DEVICE_ADD(_tag, N82077AA, 0) \ + downcast<n82077aa_device *>(device)->set_mode(_mode); -extern const device_type SMC37C78; +#define MCFG_PC_FDC_SUPERIO_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, PC_FDC_SUPERIO, 0) -class upd72065_device : public upd765a_device -{ +/* Interface required for PC ISA wrapping */ +class pc_fdc_interface : public device_t { public: - upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); -protected: - // device-level overrides - virtual void device_start(); -}; - -extern const device_type UPD72065; - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -/* RDY pin connected state */ -enum UPD765_RDY_PIN -{ - UPD765_RDY_PIN_NOT_CONNECTED = 0, - UPD765_RDY_PIN_CONNECTED = 1 -}; - -#define UPD765_DAM_DELETED_DATA 0x0f8 -#define UPD765_DAM_DATA 0x0fb - -typedef device_t *(*upd765_get_image_func)(device_t *device, int floppy_index); -#define UPD765_GET_IMAGE(name) device_t *name(device_t *device, int floppy_index ) + typedef delegate<void (bool state)> line_cb; + typedef delegate<UINT8 ()> byte_read_cb; + typedef delegate<void (UINT8)> byte_write_cb; + pc_fdc_interface(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, type, name, tag, owner, clock) {} -struct upd765_interface -{ - /* interrupt issued */ - devcb_write_line out_int_func; + virtual void setup_intrq_cb(line_cb cb) = 0; + virtual void setup_drq_cb(line_cb cb) = 0; - /* dma data request */ - devcb_write_line out_drq_func; + /* Note that the address map must cover and handle the whole 0-7 + * range. The upd765, while conforming to the rest of the + * interface, is not eligible as a result. + */ - /* image lookup */ - upd765_get_image_func get_image; + virtual DECLARE_ADDRESS_MAP(map, 8) = 0; - UPD765_RDY_PIN rdy_pin; + virtual UINT8 dma_r() = 0; + virtual void dma_w(UINT8 data) = 0; - const char *floppy_drive_tags[4]; + virtual void tc_w(bool val) = 0; + virtual UINT8 do_dir_r() = 0; }; +class upd765_family_device : public pc_fdc_interface { +public: + enum { MODE_AT, MODE_PS2, MODE_M30 }; -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ - -/* read of data register */ -DECLARE_READ8_DEVICE_HANDLER(upd765_data_r); -/* write to data register */ -DECLARE_WRITE8_DEVICE_HANDLER(upd765_data_w); -/* read of main status register */ -DECLARE_READ8_DEVICE_HANDLER(upd765_status_r); + upd765_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); -/* dma acknowledge with write */ -DECLARE_WRITE8_DEVICE_HANDLER(upd765_dack_w); -/* dma acknowledge with read */ -DECLARE_READ8_DEVICE_HANDLER(upd765_dack_r); + void setup_intrq_cb(line_cb cb); + void setup_drq_cb(line_cb cb); -/* reset upd765 */ -void upd765_reset(device_t *device, int); + virtual DECLARE_ADDRESS_MAP(map, 8) = 0; -/* reset pin of upd765 */ -WRITE_LINE_DEVICE_HANDLER(upd765_reset_w); + DECLARE_READ8_MEMBER (sra_r); + DECLARE_READ8_MEMBER (srb_r); + DECLARE_READ8_MEMBER (dor_r); + DECLARE_WRITE8_MEMBER(dor_w); + DECLARE_READ8_MEMBER (tdr_r); + DECLARE_WRITE8_MEMBER(tdr_w); + DECLARE_READ8_MEMBER (msr_r); + DECLARE_WRITE8_MEMBER(dsr_w); + DECLARE_READ8_MEMBER (fifo_r); + DECLARE_WRITE8_MEMBER(fifo_w); + DECLARE_READ8_MEMBER (dir_r); + DECLARE_WRITE8_MEMBER(ccr_w); -/* set upd765 terminal count input state */ -WRITE_LINE_DEVICE_HANDLER(upd765_tc_w); + virtual UINT8 do_dir_r(); -/* set upd765 ready input*/ -WRITE_LINE_DEVICE_HANDLER(upd765_ready_w); + UINT8 dma_r(); + void dma_w(UINT8 data); -void upd765_idle(device_t *device); -void upd765_set_bad(device_t *device, int state); + // Same as the previous ones, but as memory-mappable members + DECLARE_READ8_MEMBER(mdma_r); + DECLARE_WRITE8_MEMBER(mdma_w); -READ_LINE_DEVICE_HANDLER( upd765_int_r ); -READ_LINE_DEVICE_HANDLER( upd765_drq_r ); + bool get_irq() const; + bool get_drq() const; + void tc_w(bool val); + void ready_w(bool val); -/*********************/ -/* STATUS REGISTER 1 */ + void set_rate(int rate); // rate in bps, to be used when the fdc is externally frequency-controlled -/* this is set if a TC signal was not received after the sector data was read */ -#define UPD765_ST1_END_OF_CYLINDER (1<<7) -/* this is set if the sector ID being searched for is not found */ -#define UPD765_ST1_NO_DATA (1<<2) -/* set if disc is write protected and a write/format operation was performed */ -#define UPD765_ST1_NOT_WRITEABLE (1<<1) + void set_mode(int mode); + void set_ready_line_connected(bool ready); + void set_select_lines_connected(bool select); + void set_floppy(floppy_image_device *image); -/*********************/ -/* STATUS REGISTER 2 */ +protected: + virtual void device_start(); + virtual void device_reset(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + enum { + TIMER_DRIVE_READY_POLLING = 4 + }; + + enum { + PHASE_CMD, PHASE_EXEC, PHASE_RESULT + }; + + enum { + MSR_DB = 0x0f, + MSR_CB = 0x10, + MSR_EXM = 0x20, + MSR_DIO = 0x40, + MSR_RQM = 0x80, + + ST0_UNIT = 0x07, + ST0_NR = 0x08, + ST0_EC = 0x10, + ST0_SE = 0x20, + ST0_FAIL = 0x40, + ST0_UNK = 0x80, + ST0_ABRT = 0xc0, + + ST1_MA = 0x01, + ST1_NW = 0x02, + ST1_ND = 0x04, + ST1_OR = 0x10, + ST1_DE = 0x20, + ST1_EN = 0x80, + + ST2_MD = 0x01, + ST2_BC = 0x02, + ST2_SN = 0x04, + ST2_SH = 0x08, + ST2_WC = 0x10, + ST2_DD = 0x20, + ST2_CM = 0x40, + + ST3_UNIT = 0x07, + ST3_TS = 0x08, + ST3_T0 = 0x10, + ST3_RY = 0x20, + ST3_WP = 0x40, + ST3_FT = 0x80, + + FIF_THR = 0x0f, + FIF_POLL = 0x10, + FIF_DIS = 0x20, + FIF_EIS = 0x40, + + SPEC_ND = 0x0001, + }; + + + enum { + // General "doing nothing" state + IDLE, + + // Main states + RECALIBRATE, + SEEK, + READ_DATA, + WRITE_DATA, + READ_TRACK, + FORMAT_TRACK, + READ_ID, + + // Sub-states + COMMAND_DONE, + + SEEK_MOVE, + SEEK_WAIT_STEP_SIGNAL_TIME, + SEEK_WAIT_STEP_SIGNAL_TIME_DONE, + SEEK_WAIT_STEP_TIME, + SEEK_WAIT_STEP_TIME_DONE, + SEEK_DONE, + + HEAD_LOAD_DONE, + + WAIT_INDEX, + WAIT_INDEX_DONE, + + SCAN_ID, + SCAN_ID_FAILED, + + SECTOR_READ, + SECTOR_WRITTEN, + TC_DONE, + + TRACK_DONE, + + // Live states + SEARCH_ADDRESS_MARK_HEADER, + READ_HEADER_BLOCK_HEADER, + READ_DATA_BLOCK_HEADER, + READ_ID_BLOCK, + SEARCH_ADDRESS_MARK_DATA, + SEARCH_ADDRESS_MARK_DATA_FAILED, + READ_SECTOR_DATA, + READ_SECTOR_DATA_BYTE, + + WRITE_SECTOR_SKIP_GAP2, + WRITE_SECTOR_SKIP_GAP2_BYTE, + WRITE_SECTOR_DATA, + WRITE_SECTOR_DATA_BYTE, + + WRITE_TRACK_PRE_SECTORS, + WRITE_TRACK_PRE_SECTORS_BYTE, + + WRITE_TRACK_SECTOR, + WRITE_TRACK_SECTOR_BYTE, + + WRITE_TRACK_POST_SECTORS, + WRITE_TRACK_POST_SECTORS_BYTE, + }; + + struct pll_t { + attotime ctime, period, min_period, max_period, period_adjust_base, phase_adjust; + + attotime write_start_time; + attotime write_buffer[32]; + int write_position; + int freq_hist; + + void set_clock(attotime period); + void reset(attotime when); + int get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit); + bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, attotime limit); + void start_writing(attotime tm); + void commit(floppy_image_device *floppy, attotime tm); + void stop_writing(floppy_image_device *floppy, attotime tm); + }; + + struct floppy_info { + emu_timer *tm; + floppy_image_device *dev; + int id; + int main_state, sub_state; + int dir, counter; + UINT8 pcn; + bool irq_seek, live, index, ready, irq_polled; + }; + + struct live_info { + enum { PT_NONE, PT_CRC_1, PT_CRC_2 }; + + attotime tm; + int state, next_state; + floppy_info *fi; + UINT16 shift_reg; + UINT16 crc; + int bit_counter, byte_counter, previous_type; + bool data_separator_phase, data_bit_context; + UINT8 data_reg; + UINT8 idbuf[6]; + pll_t pll; + }; + + static int rates[4]; + + bool ready_connected, ready_polled, select_connected; + + bool external_ready; + + int mode; + int main_phase; + + live_info cur_live, checkpoint_live; + line_cb intrq_cb, drq_cb; + bool cur_irq, data_irq, drq, internal_drq, tc, tc_done; + floppy_info flopi[4]; + + int fifo_pos, fifo_expected, command_pos, result_pos; + bool fifo_write; + UINT8 dor, dsr, msr, fifo[16], command[16], result[16]; + UINT8 st0, st1, st2, st3; + UINT8 fifocfg, dor_reset; + UINT16 spec; + int sector_size; + int cur_rate; + + emu_timer *poll_timer; + + static astring tts(attotime t); + astring ttsn(); + + enum { + C_CONFIGURE, + C_FORMAT_TRACK, + C_PERPENDICULAR, + C_READ_DATA, + C_READ_ID, + C_READ_TRACK, + C_RECALIBRATE, + C_SEEK, + C_SENSE_DRIVE_STATUS, + C_SENSE_INTERRUPT_STATUS, + C_SPECIFY, + C_WRITE_DATA, + + C_INVALID, + C_INCOMPLETE, + }; + + void delay_cycles(emu_timer *tm, int cycles); + void check_irq(); + void fifo_expect(int size, bool write); + void fifo_push(UINT8 data, bool internal); + UINT8 fifo_pop(bool internal); + void set_drq(bool state); + bool get_ready(int fid); + + void enable_transfer(); + void disable_transfer(); + int calc_sector_size(UINT8 size); + + void run_drive_ready_polling(); + + int check_command(); + void start_command(int cmd); + void command_end(floppy_info &fi, bool data_completion); + + void recalibrate_start(floppy_info &fi); + void seek_start(floppy_info &fi); + void seek_continue(floppy_info &fi); + + void read_data_start(floppy_info &fi); + void read_data_continue(floppy_info &fi); + + void write_data_start(floppy_info &fi); + void write_data_continue(floppy_info &fi); + + void read_track_start(floppy_info &fi); + void read_track_continue(floppy_info &fi); + + void format_track_start(floppy_info &fi); + void format_track_continue(floppy_info &fi); + + void read_id_start(floppy_info &fi); + void read_id_continue(floppy_info &fi); + + void general_continue(floppy_info &fi); + void index_callback(floppy_image_device *floppy, int state); + bool sector_matches() const; + + void live_start(floppy_info &fi, int live_state); + void live_abort(); + void checkpoint(); + void rollback(); + void live_delay(int state); + void live_sync(); + void live_run(attotime limit = attotime::never); + void live_write_raw(UINT16 raw); + void live_write_mfm(UINT8 mfm); + + bool read_one_bit(attotime limit); + bool write_one_bit(attotime limit); +}; -/* C parameter specified did not match C value read from disc */ -#define UPD765_ST2_WRONG_CYLINDER (1<<4) -/* C parameter specified did not match C value read from disc, and C read from disc was 0x0ff */ -#define UPD765_ST2_BAD_CYLINDER (1<<1) -/* this is set if the FDC encounters a Deleted Data Mark when executing a read data -command, or FDC encounters a Data Mark when executing a read deleted data command */ -#define UPD765_ST2_CONTROL_MARK (1<<6) +class upd765a_device : public upd765_family_device { +public: + upd765a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); -/*************************************************************************** - DEVICE CONFIGURATION MACROS -***************************************************************************/ + virtual DECLARE_ADDRESS_MAP(map, 8); +}; -#define MCFG_UPD765A_ADD(_tag, _intrf) \ - MCFG_DEVICE_ADD(_tag, UPD765A, 0) \ - MCFG_DEVICE_CONFIG(_intrf) +class upd765b_device : public upd765_family_device { +public: + upd765b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); -#define MCFG_UPD765A_MODIFY(_tag, _intrf) \ - MCFG_DEVICE_MODIFY(_tag) \ - MCFG_DEVICE_CONFIG(_intrf) + virtual DECLARE_ADDRESS_MAP(map, 8); +}; -#define MCFG_UPD765A_REMOVE(_tag) \ - MCFG_DEVICE_REMOVE(_tag) +class i8272a_device : public upd765_family_device { +public: + i8272a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); -#define MCFG_UPD765B_ADD(_tag, _intrf) \ - MCFG_DEVICE_ADD(_tag, UPD765B, 0) \ - MCFG_DEVICE_CONFIG(_intrf) + virtual DECLARE_ADDRESS_MAP(map, 8); +}; -#define MCFG_UPD765B_MODIFY(_tag, _intrf) \ - MCFG_DEVICE_MODIFY(_tag) \ - MCFG_DEVICE_CONFIG(_intrf) +class smc37c78_device : public upd765_family_device { +public: + smc37c78_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); -#define MCFG_UPD765B_REMOVE(_tag) \ - MCFG_DEVICE_REMOVE(_tag) + virtual DECLARE_ADDRESS_MAP(map, 8); +}; -#define MCFG_SMC37C78_ADD(_tag, _intrf) \ - MCFG_DEVICE_ADD(_tag, SMC37C78, 0) \ - MCFG_DEVICE_CONFIG(_intrf) +class upd72065_device : public upd765_family_device { +public: + upd72065_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); -#define MCFG_SMC37C78_MODIFY(_tag, _intrf) \ - MCFG_DEVICE_MODIFY(_tag) \ - MCFG_DEVICE_CONFIG(_intrf) + virtual DECLARE_ADDRESS_MAP(map, 8); +}; -#define MCFG_SMC37C78_REMOVE(_tag) \ - MCFG_DEVICE_REMOVE(_tag) +class n82077aa_device : public upd765_family_device { +public: + n82077aa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); -#define MCFG_UPD72065_ADD(_tag, _intrf) \ - MCFG_DEVICE_ADD(_tag, UPD72065, 0) \ - MCFG_DEVICE_CONFIG(_intrf) + virtual DECLARE_ADDRESS_MAP(map, 8); +}; -#define MCFG_UPD72065_MODIFY(_tag, _intrf) \ - MCFG_DEVICE_MODIFY(_tag) \ - MCFG_DEVICE_CONFIG(_intrf) +class pc_fdc_superio_device : public upd765_family_device { +public: + pc_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); -#define MCFG_UPD72065_REMOVE(_tag) \ - MCFG_DEVICE_REMOVE(_tag) + virtual DECLARE_ADDRESS_MAP(map, 8); +}; +extern const device_type UPD765A; +extern const device_type UPD765B; +extern const device_type I8272A; +extern const device_type UPD72065; +extern const device_type SMC37C78; +extern const device_type N82077AA; +extern const device_type PC_FDC_SUPERIO; -#endif /* __UPD765_H__ */ +#endif |