From 27d2ae2cf6d84e608204583bdf97f711fb0cd80c Mon Sep 17 00:00:00 2001 From: 68bit Date: Wed, 31 Jul 2019 11:26:04 +1000 Subject: [PATCH] swtpc09: add hard disk support for the DMAF3 controller This uses the WD1000 driver. The DMAF2/3 6844 DMA support had to be improved to support multiple channels, and now supports a separate high addresses for each channel. It now also support addresses increasing or decreasing. These controllers use different DMA channels for the floppy and the hard disk, and also a tape archiver which is not yet implemented. This gets UniFLEX running using a hard disk for storage, and does not appear to regress the floppy support or other variants using the DMAF2. --- src/devices/machine/wd1000.cpp | 4 - src/mame/drivers/swtpc09.cpp | 40 +++- src/mame/includes/swtpc09.h | 50 ++++- src/mame/machine/swtpc09.cpp | 349 +++++++++++++++++++++++++-------- 4 files changed, 339 insertions(+), 104 deletions(-) diff --git a/src/devices/machine/wd1000.cpp b/src/devices/machine/wd1000.cpp index ede5021be66..a1d969bf008 100644 --- a/src/devices/machine/wd1000.cpp +++ b/src/devices/machine/wd1000.cpp @@ -470,10 +470,7 @@ WRITE8_MEMBER( wd1000_device::write ) // bit 6,5 : sector size (0: 256, 1: 512, 3: 128) // bit 4,3 : drive select (0,1,2,3) // bit 2,1,0: head select (0-7) - uint8_t ecc = BIT(data, 7); - uint8_t sec_size = (data & 0x60) >> 5; uint8_t drive = (data & 0x18) >> 3; - uint8_t head = data & 0x7; m_sdh = data; // Update the drive ready flag in the status register which @@ -564,7 +561,6 @@ void wd1000_device::cmd_restore() void wd1000_device::cmd_read_sector() { hard_disk_file *file = m_drives[drive()].drive->get_hard_disk_file(); - hard_disk_info *info = hard_disk_get_info(file); uint8_t dma = BIT(m_command, 3); hard_disk_read(file, get_lbasector(), m_buffer); diff --git a/src/mame/drivers/swtpc09.cpp b/src/mame/drivers/swtpc09.cpp index 9760351c7f4..6b7b85ba262 100644 --- a/src/mame/drivers/swtpc09.cpp +++ b/src/mame/drivers/swtpc09.cpp @@ -26,7 +26,6 @@ #include "emu.h" #include "includes/swtpc09.h" #include "bus/ss50/interface.h" -#include "machine/input_merger.h" #include "formats/flex_dsk.h" #include "formats/uniflex_dsk.h" @@ -49,7 +48,7 @@ F000 - F01F DMAF2 MC6844 DMAC F020 - F023 DMAF2 WD1791 FDC F024 - F03F DMAF2 Drive select register - F040 - F041 DMAF2 DMA Address register + F040 - F041 DMAF2 DMA Address register, and interrupt enable, latch. F800 - FFFF ROM FFF0 - FFFF DAT RAM (only for writes) @@ -59,9 +58,17 @@ F000 - F01F DMAF3 MC6844 DMAC F020 - F023 DMAF3 WD1791 FDC F024 - F024 DMAF3 Drive select register - F025 - F025 DMAF3 DMA Address register - F030 - F03F DMAF3 WD1000 - F040 - F04F DMAF3 6522 VIA + F025 - F025 DMAF3 74LS374 latch for 4 extended address lines (bits 0-3), DMA. + F030 - F03F DMAF3 HDC WD1000 + F040 - F04F DMAF3 VIA6522 + F050 - F050 DMAF3 HDC head load toggle + F051 - F051 DMAF3 Winchester software reset + F052 - F052 DMAF3 Archive reset + F053 - F053 DMAF3 Archive clear + F060 - ???? DMAF3 archive DMA preset + + F100 - ???? CDS disk 0 controller + F300 - ???? CDS disk 1 controller ***************************************************************************/ @@ -92,10 +99,12 @@ void swtpc09_state::flex_dmaf2_mem(address_map &map) // MPID map(0xfe080, 0xfe083).mirror(0xc).rw(m_pia, FUNC(pia6821_device::read), FUNC(pia6821_device::write)); map(0xfe090, 0xfe097).mirror(0x8).rw(m_ptm, FUNC(ptm6840_device::read), FUNC(ptm6840_device::write)); + // DMAF2 map(0xff000, 0xff01f).rw(FUNC(swtpc09_state::m6844_r), FUNC(swtpc09_state::m6844_w)); map(0xff020, 0xff023).rw(FUNC(swtpc09_state::dmaf2_fdc_r), FUNC(swtpc09_state::dmaf2_fdc_w)); map(0xff024, 0xff03f).rw(FUNC(swtpc09_state::dmaf2_control_reg_r), FUNC(swtpc09_state::dmaf2_control_reg_w)); + map(0xff040, 0xff040).rw(FUNC(swtpc09_state::dmaf2_dma_address_reg_r), FUNC(swtpc09_state::dmaf2_dma_address_reg_w)); map(0xff800, 0xfffff).rom().region("bankdev", 0xff800); } @@ -178,10 +187,12 @@ void swtpc09_state::uniflex_dmaf3_mem(address_map &map) map(0xff020, 0xff023).rw(FUNC(swtpc09_state::dmaf3_fdc_r), FUNC(swtpc09_state::dmaf3_fdc_w)); map(0xff024, 0xff024).rw(FUNC(swtpc09_state::dmaf3_control_reg_r), FUNC(swtpc09_state::dmaf3_control_reg_w)); map(0xff025, 0xff025).rw(FUNC(swtpc09_state::dmaf3_dma_address_reg_r), FUNC(swtpc09_state::dmaf3_dma_address_reg_w)); + map(0xff030, 0xff03f).rw(m_hdc, FUNC(wd1000_device::read), FUNC(wd1000_device::write)); map(0xff040, 0xff04f).m(m_via, FUNC(via6522_device::map)); - - // DMAF3 WD1000 - map(0xff030, 0xff03f).rw(FUNC(swtpc09_state::dmaf3_wd_r), FUNC(swtpc09_state::dmaf3_wd_w)); + map(0xff050, 0xff050).rw(FUNC(swtpc09_state::dmaf3_hdc_control_r), FUNC(swtpc09_state::dmaf3_hdc_control_w)); + map(0xff051, 0xff051).rw(FUNC(swtpc09_state::dmaf3_hdc_reset_r), FUNC(swtpc09_state::dmaf3_hdc_reset_w)); + map(0xff052, 0xff052).rw(FUNC(swtpc09_state::dmaf3_archive_reset_r), FUNC(swtpc09_state::dmaf3_archive_reset_w)); + map(0xff053, 0xff053).rw(FUNC(swtpc09_state::dmaf3_archive_clear_r), FUNC(swtpc09_state::dmaf3_archive_clear_w)); map(0xff800, 0xfffff).rom().region("bankdev", 0xff800); } @@ -506,12 +517,25 @@ void swtpc09_state::swtpc09d3(machine_config &config) m_fdc->drq_wr_callback().set(FUNC(swtpc09_state::fdc_drq_w)); m_fdc->sso_wr_callback().set(FUNC(swtpc09_state::fdc_sso_w)); + // Hard disk + WD1000(config, m_hdc, 5_MHz_XTAL); + m_hdc->intrq_wr_callback().set(FUNC(swtpc09_state::dmaf3_hdc_intrq_w)); + m_hdc->drq_wr_callback().set(FUNC(swtpc09_state::dmaf3_hdc_drq_w)); + HARDDISK(config, "hdc:0", 0); + HARDDISK(config, "hdc:1", 0); + HARDDISK(config, "hdc:2", 0); + HARDDISK(config, "hdc:3", 0); + via6522_device &via(VIA6522(config, "via", 4_MHz_XTAL / 4)); via.readpa_handler().set(FUNC(swtpc09_state::dmaf3_via_read_porta)); via.readpb_handler().set(FUNC(swtpc09_state::dmaf3_via_read_portb)); via.writepa_handler().set(FUNC(swtpc09_state::dmaf3_via_write_porta)); + via.writepb_handler().set(FUNC(swtpc09_state::dmaf3_via_write_portb)); //via.ca1_handler().set(FUNC(swtpc09_state::dmaf3_via_write_ca1)); via.irq_handler().set(FUNC(swtpc09_state::dmaf3_via_irq)); + + INPUT_MERGER_ALL_HIGH(config, "via_cb2").output_handler().set(m_via, FUNC(via6522_device::write_cb2)); + } diff --git a/src/mame/includes/swtpc09.h b/src/mame/includes/swtpc09.h index 8dc3b9169e7..b3e310c5487 100644 --- a/src/mame/includes/swtpc09.h +++ b/src/mame/includes/swtpc09.h @@ -18,7 +18,9 @@ #include "machine/6840ptm.h" #include "machine/6821pia.h" #include "machine/6522via.h" +#include "machine/input_merger.h" #include "imagedev/harddriv.h" +#include "machine/wd1000.h" #include "machine/bankdev.h" #include "machine/mc14411.h" @@ -37,7 +39,9 @@ public: , m_floppy1(*this, "fdc:1") , m_floppy2(*this, "fdc:2") , m_floppy3(*this, "fdc:3") + , m_hdc(*this, "hdc") , m_via(*this, "via") + , m_via_cb2(*this, "via_cb2") , m_dat(*this, "dat") , m_bankdev(*this, "bankdev") , m_maincpu_clock(*this, "maincpu_clock") @@ -82,6 +86,7 @@ private: DECLARE_READ8_MEMBER( dmaf3_via_read_porta ); DECLARE_READ8_MEMBER( dmaf3_via_read_portb ); DECLARE_WRITE8_MEMBER( dmaf3_via_write_porta ); + DECLARE_WRITE8_MEMBER( dmaf3_via_write_portb ); DECLARE_WRITE_LINE_MEMBER( dmaf3_via_irq ); TIMER_CALLBACK_MEMBER(floppy_motor_callback); @@ -100,8 +105,16 @@ private: DECLARE_READ8_MEMBER ( dmaf3_control_reg_r ); DECLARE_WRITE8_MEMBER ( dmaf3_control_reg_w ); - DECLARE_READ8_MEMBER( dmaf3_wd_r ); - DECLARE_WRITE8_MEMBER( dmaf3_wd_w ); + DECLARE_WRITE_LINE_MEMBER(dmaf3_hdc_intrq_w); + DECLARE_WRITE_LINE_MEMBER( dmaf3_hdc_drq_w ); + DECLARE_READ8_MEMBER( dmaf3_hdc_control_r ); + DECLARE_WRITE8_MEMBER( dmaf3_hdc_control_w ); + DECLARE_READ8_MEMBER( dmaf3_hdc_reset_r ); + DECLARE_WRITE8_MEMBER( dmaf3_hdc_reset_w ); + DECLARE_READ8_MEMBER( dmaf3_archive_reset_r ); + DECLARE_WRITE8_MEMBER( dmaf3_archive_reset_w ); + DECLARE_READ8_MEMBER( dmaf3_archive_clear_r ); + DECLARE_WRITE8_MEMBER( dmaf3_archive_clear_w ); DECLARE_WRITE8_MEMBER(dat_w); DECLARE_READ8_MEMBER(main_r); @@ -122,7 +135,6 @@ private: virtual void machine_start() override; virtual void machine_reset() override; - void swtpc09_fdc_dma_transfer(); void swtpc09_irq_handler(uint8_t peripheral, uint8_t state); void floppy_motor_trigger(); @@ -144,7 +156,10 @@ private: optional_device m_floppy2; optional_device m_floppy3; + optional_device m_hdc; + optional_device m_via; + optional_device m_via_cb2; required_shared_ptr m_dat; required_device m_bankdev; required_ioport m_maincpu_clock; @@ -158,15 +173,17 @@ private: uint8_t m_pia_counter; // this is the counter on pia porta - uint8_t m_fdc_dma_address_reg; // dmaf2 or dmaf3 dma extended address reg + uint8_t m_dmaf_high_address[4]; // dmaf2 or dmaf3 dma extended address reg + uint8_t m_dmaf2_interrupt_enable; + uint8_t m_system_type; // flag to indicate hw and rom combination uint8_t m_fdc_status; // for floppy controller int m_floppy_motor_on; emu_timer *m_floppy_motor_timer; floppy_image_device *m_fdc_floppy; // Current selected floppy. uint8_t m_fdc_side; // Current floppy side. - uint8_t m_via_ca1_input; // dmaf3 fdc interrupt is connected here uint8_t m_dmaf3_via_porta; + uint8_t m_dmaf3_via_portb; uint8_t m_active_interrupt; uint8_t m_interrupt; @@ -180,6 +197,20 @@ private: int active; int address; int counter; + // Channel control register. + // bit 0: Read / Write mode + // bit 1: Mode control B + // bit 2: Mode control A + // bit 3: Address up (0) / down (1). + // bit 4: Not used + // bit 5: Not used + // bit 6: Busy / Ready. Read only. Set when request + // made. Cleared when transfer completed. + // bit 7: DMA end flag. Read only? Set when transfer + // completed. Cleared when control register + // read. Sets IRQ. + // Mode control A,B: 0,0 Mode2; 0,1 Mode 3; 1,0 Mode 0; + // 1,1 Undefined. uint8_t control; int start_address; int start_counter; @@ -188,8 +219,17 @@ private: /* 6844 description */ m6844_channel_data m_m6844_channel[4]; uint8_t m_m6844_priority; + // Interrupt control register. + // Bit 0-3: channel interrupt enable, 1 enabled, 0 masked. + // Bit 4-6: unused + // Bit 7: Read only. Set to 1 when IRQ asserted. Clear when the + // control register associated with the channel that caused the + // interrut is read. uint8_t m_m6844_interrupt; uint8_t m_m6844_chain; + void m6844_update_interrupt(); + void m6844_fdc_dma_transfer(uint8_t channel); + void m6844_hdc_dma_transfer(uint8_t channel); }; #endif // MAME_INCLUDES_SWTPC09_H diff --git a/src/mame/machine/swtpc09.cpp b/src/mame/machine/swtpc09.cpp index bbf8c34e9d2..ad84096fc79 100644 --- a/src/mame/machine/swtpc09.cpp +++ b/src/mame/machine/swtpc09.cpp @@ -227,8 +227,6 @@ WRITE8_MEMBER ( swtpc09_state::dmaf2_fdc_w ) // TODO Does access to the dmaf2 fdc also trigger the motor timer. floppy_motor_trigger(); - // TODO how does the DMAF2 use the FDC SSO output? - if (offset == 0) { validate_floppy_side(data); data = validate_fdc_sector_size(data); @@ -237,24 +235,37 @@ WRITE8_MEMBER ( swtpc09_state::dmaf2_fdc_w ) m_fdc->fd1797_device::write(offset, data); } -/* DMAF2 dma extended address register */ +/* DMAF2 dma extended address register latch. */ + READ8_MEMBER ( swtpc09_state::dmaf2_dma_address_reg_r ) { - return m_fdc_dma_address_reg; + // This does not appear to be readable. + logerror("%s Unexpected read of DMAF2 DMA address reg\n", machine().describe_context()); + return 0x00; } WRITE8_MEMBER ( swtpc09_state::dmaf2_dma_address_reg_w ) { - m_fdc_dma_address_reg = data; + // This latch appears to be write-only, there is no reader function. + // The DMAF2 has a single latch for the high address bits, so it would + // appear to apply for all DMA channels. These outputs are inverted + // which cancels the inversion of the data lines. + m_dmaf_high_address[0] = data & 0x0f; + m_dmaf_high_address[1] = data & 0x0f; + m_dmaf_high_address[2] = data & 0x0f; + m_dmaf_high_address[3] = data & 0x0f; // bit 4 controls a gate enable/disable for DMAF2 fdc irq line - if ((m_fdc_dma_address_reg & 0x10) && (m_system_type == UNIFLEX_DMAF2 || m_system_type == FLEX_DMAF2)) + m_dmaf2_interrupt_enable = !BIT(data, 4); + if (!m_dmaf2_interrupt_enable) swtpc09_irq_handler(FDC_IRQ, CLEAR_LINE); //then clear the irq to cpu } /* DMAF2 fdc control register */ READ8_MEMBER ( swtpc09_state::dmaf2_control_reg_r ) { + // TODO is this readable? + logerror("%s Unexpected read from DMAF2 control reg\n", machine().describe_context()); return m_fdc_status; } @@ -262,71 +273,33 @@ WRITE8_MEMBER ( swtpc09_state::dmaf2_control_reg_w ) { floppy_image_device *floppy = nullptr; - // TODO what to do if multiple drives are selected? - if (!BIT(data, 0) + !BIT(data, 1) + !BIT(data, 2) + !BIT(data, 3) > 1) - { - logerror("%s Unexpected DMAF2 has multiple drives selected: %d %d %d %d\n", machine().describe_context(), !BIT(data, 0), !BIT(data, 1), !BIT(data, 2), !BIT(data, 3)); - } + // The DMAF2 data lines are inverted. + data = ~data & 0xff; - if (!BIT(data, 0)) floppy = m_floppy0->get_device(); - if (!BIT(data, 1)) floppy = m_floppy1->get_device(); - if (!BIT(data, 2)) floppy = m_floppy2->get_device(); - if (!BIT(data, 3)) floppy = m_floppy3->get_device(); + // TODO what to do if multiple drives are selected? + if (BIT(data, 0) + BIT(data, 1) + BIT(data, 2) + BIT(data, 3) > 1) + logerror("%s Unexpected DMAF2 has multiple drives selected: %d %d %d %d\n", machine().describe_context(), BIT(data, 0), BIT(data, 1), BIT(data, 2), BIT(data, 3)); + + if (BIT(data, 0)) floppy = m_floppy0->get_device(); + if (BIT(data, 1)) floppy = m_floppy1->get_device(); + if (BIT(data, 2)) floppy = m_floppy2->get_device(); + if (BIT(data, 3)) floppy = m_floppy3->get_device(); m_fdc->set_floppy(floppy); m_fdc_floppy = floppy; if (floppy) { - uint8_t side = !BIT(data, 4); + uint8_t side = BIT(data, 4); floppy->ss_w(side); m_fdc_side = side; } - uint8_t dden = !BIT(data, 5); + uint8_t dden = BIT(data, 5); dden = validate_fdc_dden(dden); m_fdc->dden_w(dden); } -/* FDC controller dma transfer */ -void swtpc09_state::swtpc09_fdc_dma_transfer() -{ - uint32_t offset; - address_space &space = *m_banked_space; - - offset = (m_fdc_dma_address_reg & 0x0f)<<16; - - if (m_m6844_channel[0].active == 1) //active dma transfer - { - if (!(m_m6844_channel[0].control & 0x01)) // dma write to memory - { - uint8_t data = m_fdc->data_r(); - - space.write_byte(m_m6844_channel[0].address + offset, data); - } - else - { - uint8_t data = space.read_byte(m_m6844_channel[0].address + offset); - - m_fdc->data_w(data); - } - - m_m6844_channel[0].address++; - m_m6844_channel[0].counter--; - - if (m_m6844_channel[0].counter == 0) // dma transfer has finished - { - m_m6844_channel[0].control |= 0x80; // set dend flag - if (m_m6844_interrupt & 0x01) // interrupt for channel 0 is enabled? - { - m_m6844_interrupt |= 0x80; // set bit 7 to indicate active interrupt - swtpc09_irq_handler(DMAC_IRQ, ASSERT_LINE); - } - } - } - -} - /* common interrupt handler */ void swtpc09_state::swtpc09_irq_handler(uint8_t peripheral, uint8_t state) { @@ -356,22 +329,26 @@ void swtpc09_state::swtpc09_irq_handler(uint8_t peripheral, uint8_t state) /* handlers for fdc */ WRITE_LINE_MEMBER( swtpc09_state::fdc_intrq_w ) { - if ( m_system_type == UNIFLEX_DMAF3 ) //IRQ from 1791 is connect into VIA ca2 + if ( m_system_type == UNIFLEX_DMAF3 ) { + // IRQ from 1791 is connected into VIA CB2 inverted, and + // connected to VIA port B bit 2 without inversion. if (state) { m_fdc_status |= 0x40; - m_via->write_cb2(0); //fdc interrupt is connected to CA1 - m_dmaf3_via_porta &= 0xfb; //clear pa3 - //m_via->write_porta(m_dmaf3_via_porta); //and connected to PA3 + //m_via->write_cb2(0); + m_via_cb2->in_w<0>(0); + m_dmaf3_via_portb |= 0x04; + //m_via->write_portb(m_dmaf3_via_portb); //swtpc09_irq_handler(FDC_IRQ, ASSERT_LINE); } else { m_fdc_status &= ~0x40; - m_via->write_cb2(1); - m_dmaf3_via_porta |= 0x04; //and connected to PA3 - //m_via->write_porta(m_dmaf3_via_porta); //and connected to PA3 + //m_via->write_cb2(1); + m_via_cb2->in_w<0>(1); + m_dmaf3_via_portb &= 0xfb; + //m_via->write_portb(m_dmaf3_via_portb); //swtpc09_irq_handler(FDC_IRQ, CLEAR_LINE); } } @@ -380,7 +357,7 @@ WRITE_LINE_MEMBER( swtpc09_state::fdc_intrq_w ) if (state) { m_fdc_status |= 0x40; - if (!(m_fdc_dma_address_reg & 0x10)) // is dmaf2 fdc irq enabled + if (m_dmaf2_interrupt_enable) { swtpc09_irq_handler(FDC_IRQ, ASSERT_LINE); } @@ -388,7 +365,7 @@ WRITE_LINE_MEMBER( swtpc09_state::fdc_intrq_w ) else { m_fdc_status &= ~0x40; - if (!(m_fdc_dma_address_reg & 0x10)) // is dmaf2 fdc irq enabled + if (m_dmaf2_interrupt_enable) { swtpc09_irq_handler(FDC_IRQ, CLEAR_LINE); } @@ -401,7 +378,9 @@ WRITE_LINE_MEMBER( swtpc09_state::fdc_drq_w ) if (state) { m_fdc_status |= 0x80; - swtpc09_fdc_dma_transfer(); + // The DMAF2 schematic shows an input to two pins on the 6844, + // it might also trigger channel 1. + m6844_fdc_dma_transfer(0); } else m_fdc_status &= 0x7f; @@ -409,7 +388,7 @@ WRITE_LINE_MEMBER( swtpc09_state::fdc_drq_w ) WRITE_LINE_MEMBER( swtpc09_state::fdc_sso_w ) { - // Doese the DMAF2 or DMAF3 use the SSO output? + // The DMAF2 and DMAF3 do not appear to use a SSO output? } /*********************************************************************/ @@ -445,7 +424,18 @@ READ8_MEMBER( swtpc09_state::dmaf3_via_read_porta ) READ8_MEMBER( swtpc09_state::dmaf3_via_read_portb ) { - return 0xff; + // Bit 0 - output ? + // Bit 1 - output, tape drive request strobe. + // Bit 2 - input, WD1791 FDC interrupt. + // Bit 3 - input ? + // Bit 4 - input, tape drive ready + // Bit 5 - input, tape drive exception, timer 2. + // Bit 6 - input ? + // Bit 7 - output, UniFLEX configures a timer to toggle this output. + + // Set the tape drive exception bit to avoid detection, otherwise + // UniFLEX gets stuck in a loop trying to open the archive driver. + return m_dmaf3_via_portb | 0x20; } WRITE8_MEMBER( swtpc09_state::dmaf3_via_write_porta ) @@ -453,6 +443,11 @@ WRITE8_MEMBER( swtpc09_state::dmaf3_via_write_porta ) m_dmaf3_via_porta &= data; } +WRITE8_MEMBER( swtpc09_state::dmaf3_via_write_portb ) +{ + m_dmaf3_via_portb &= data; +} + //WRITE_LINE_MEMBER( swtpc09_state::dmaf3_via_write_ca1 ) //{ // return m_via_ca1_input; @@ -471,17 +466,28 @@ WRITE_LINE_MEMBER( swtpc09_state::dmaf3_via_irq ) /* DMAF3 dma extended address register */ READ8_MEMBER ( swtpc09_state::dmaf3_dma_address_reg_r ) { - return m_fdc_dma_address_reg; + // TODO is this readable? + logerror("%s Unexpected read of DMAF3 DMA address reg\n", machine().describe_context()); + return 0x00; } WRITE8_MEMBER ( swtpc09_state::dmaf3_dma_address_reg_w ) { - m_fdc_dma_address_reg = data; + // Based on source code comments it appears that there are four high + // address latches, one for each DMA channel. TODO check hardware or a + // schematic. + uint8_t channel = (data & 0x30) >> 4; + m_dmaf_high_address[channel] = data & 0x0f; + + // Bit 6 controls the 'archive edge select'. + // Bit 7 controls the DMA halt versus bus-req mode. } /* DMAF3 fdc control register */ READ8_MEMBER ( swtpc09_state::dmaf3_control_reg_r ) { + // TODO is this readable? + logerror("%s Unexpected read from DMAF3 control reg\n", machine().describe_context()); return m_fdc_status; } @@ -491,9 +497,7 @@ WRITE8_MEMBER ( swtpc09_state::dmaf3_control_reg_w ) // TODO multiple selected? if (BIT(data, 0) + BIT(data, 1) + BIT(data, 2) + BIT(data, 3) > 1) - { - logerror("%s Unexpected DMAF3 has multiple drives selected: %d %d %d %d\n", machine().describe_context(), !BIT(data, 0), !BIT(data, 1), !BIT(data, 2), !BIT(data, 3)); - } + logerror("%s Unexpected DMAF3 has multiple drives selected: %d %d %d %d\n", machine().describe_context(), BIT(data, 0), BIT(data, 1), BIT(data, 2), BIT(data, 3)); if (BIT(data, 0)) floppy = m_floppy0->get_device(); if (BIT(data, 1)) floppy = m_floppy1->get_device(); @@ -515,17 +519,74 @@ WRITE8_MEMBER ( swtpc09_state::dmaf3_control_reg_w ) m_fdc->dden_w(dden); } -// DMAF3 WD1000 -// TODO. The following might help: -// http://www.bitsavers.org/pdf/westernDigital/WD100x/WD1000_OEM_Manual.pdf +// DMAF3 WD1000 hard disk controller. -READ8_MEMBER( swtpc09_state::dmaf3_wd_r ) +WRITE_LINE_MEMBER( swtpc09_state::dmaf3_hdc_intrq_w ) { - return 0x00; + // The IRQ from WD1000 is connected into VIA CB2 inverted, and perhaps + // connected to a VIA port B bit 3? + if (state) + { + m_via_cb2->in_w<1>(0); + //m_dmaf3_via_portb &= 0xf7; + //m_via->write_portb(m_dmaf3_via_portb); + } + else + { + m_via_cb2->in_w<1>(1); + //m_dmaf3_via_portb |= 0x08; + //m_via->write_portb(m_dmaf3_via_portb); + } } -WRITE8_MEMBER ( swtpc09_state::dmaf3_wd_w ) +WRITE_LINE_MEMBER( swtpc09_state::dmaf3_hdc_drq_w ) { + if (state) + m6844_hdc_dma_transfer(1); +} + +READ8_MEMBER( swtpc09_state::dmaf3_hdc_control_r ) +{ + // TODO head load toggle? + return 0; +} + +WRITE8_MEMBER ( swtpc09_state::dmaf3_hdc_control_w ) +{ + // TODO head load toggle? +} + +READ8_MEMBER( swtpc09_state::dmaf3_hdc_reset_r ) +{ + // TODO reset? + return 0; +} + +WRITE8_MEMBER ( swtpc09_state::dmaf3_hdc_reset_w ) +{ + // TODO reset +} + +READ8_MEMBER( swtpc09_state::dmaf3_archive_reset_r ) +{ + // TODO + return 0; +} + +WRITE8_MEMBER ( swtpc09_state::dmaf3_archive_reset_w ) +{ + // TODO +} + +READ8_MEMBER( swtpc09_state::dmaf3_archive_clear_r ) +{ + // TODO + return 0; +} + +WRITE8_MEMBER ( swtpc09_state::dmaf3_archive_clear_w ) +{ + // TODO } @@ -566,6 +627,110 @@ WRITE8_MEMBER(swtpc09_state::main_w) /* MC6844 DMA controller I/O */ + +void swtpc09_state::m6844_update_interrupt() +{ + uint8_t interrupt = 0; + + interrupt |= BIT(m_m6844_channel[0].control, 7) & BIT(m_m6844_interrupt, 0); + interrupt |= BIT(m_m6844_channel[1].control, 7) & BIT(m_m6844_interrupt, 1); + interrupt |= BIT(m_m6844_channel[2].control, 7) & BIT(m_m6844_interrupt, 2); + interrupt |= BIT(m_m6844_channel[3].control, 7) & BIT(m_m6844_interrupt, 3); + + if (interrupt) + { + if (!(m_m6844_interrupt & 0x80)) + { + // Set interrupt indication bit 7. + m_m6844_interrupt |= 0x80; + swtpc09_irq_handler(DMAC_IRQ, ASSERT_LINE); + } + } + else + { + if (m_m6844_interrupt & 0x80) + { + // Clear interrupt indication bit 7. + m_m6844_interrupt &= 0x7f; + swtpc09_irq_handler(DMAC_IRQ, CLEAR_LINE); + } + } +} + +void swtpc09_state::m6844_fdc_dma_transfer(uint8_t channel) +{ + uint32_t offset; + address_space &space = *m_banked_space; + + offset = m_dmaf_high_address[channel] << 16; + + if (m_m6844_channel[channel].active == 1) //active dma transfer + { + if (!(m_m6844_channel[channel].control & 0x01)) // dma write to memory + { + uint8_t data = m_fdc->data_r(); + + space.write_byte(m_m6844_channel[channel].address + offset, data); + } + else + { + uint8_t data = space.read_byte(m_m6844_channel[channel].address + offset); + + m_fdc->data_w(data); + } + + if (m_m6844_channel[channel].control & 0x08) + m_m6844_channel[channel].address--; + else + m_m6844_channel[channel].address++; + + m_m6844_channel[channel].counter--; + + if (m_m6844_channel[channel].counter == 0) // dma transfer has finished + { + m_m6844_channel[channel].control |= 0x80; // set dend flag + m6844_update_interrupt(); + } + } +} + +void swtpc09_state::m6844_hdc_dma_transfer(uint8_t channel) +{ + uint32_t offset; + address_space &space = *m_banked_space; + + offset = m_dmaf_high_address[channel] << 16; + + if (m_m6844_channel[channel].active == 1) //active dma transfer + { + if (!(m_m6844_channel[channel].control & 0x01)) // dma write to memory + { + uint8_t data = m_hdc->data_r(); + + space.write_byte(m_m6844_channel[channel].address + offset, data); + } + else + { + uint8_t data = space.read_byte(m_m6844_channel[channel].address + offset); + + m_hdc->data_w(data); + } + + if (m_m6844_channel[channel].control & 0x08) + m_m6844_channel[channel].address--; + else + m_m6844_channel[channel].address++; + + m_m6844_channel[channel].counter--; + + if (m_m6844_channel[channel].counter == 0) // dma transfer has finished + { + m_m6844_channel[channel].control |= 0x80; // set dend flag + m6844_update_interrupt(); + } + } +} + READ8_MEMBER( swtpc09_state::m6844_r ) { uint8_t result = 0; @@ -612,15 +777,13 @@ READ8_MEMBER( swtpc09_state::m6844_r ) case 0x13: result = m_m6844_channel[offset - 0x10].control; - /* a read here clears the DMA end flag */ + // A read here clears the 'DMA end' flag of the + // associated channel. if (!machine().side_effects_disabled()) { m_m6844_channel[offset - 0x10].control &= ~0x80; - if (m_m6844_interrupt & 0x80) // if interrupt is active, then clear - { - swtpc09_irq_handler(0x01, CLEAR_LINE); - m_m6844_interrupt &= 0x7f; // clear interrupt indication bit 7 - } + if (m_m6844_interrupt & 0x80) + m6844_update_interrupt(); } break; @@ -742,6 +905,7 @@ WRITE8_MEMBER( swtpc09_state::m6844_w ) /* interrupt control */ case 0x15: m_m6844_interrupt = (m_m6844_interrupt & 0x80) | (data & 0x7f); + m6844_update_interrupt(); break; /* chaining control */ @@ -775,6 +939,11 @@ void swtpc09_state::machine_reset() m_brg->rsa_w(baud_rate_high); m_brg->rsb_w(1); + m_pia->write_portb(0); + m_pia->cb1_w(0); + m_pia->ca2_w(0); + m_pia->cb2_w(0); + // Note UNIBUG has a smarter boot loader in ROM and will toggle the // density on failure so this is not necessary for UniFLEX. if ((m_system_type == FLEX_DMAF2 || @@ -810,7 +979,12 @@ void swtpc09_state::machine_start() m_fdc_side = 0; // Start with the IRQ disabled? - m_fdc_dma_address_reg = 0x10; + m_dmaf2_interrupt_enable = 0; + + m_dmaf_high_address[0] = 0; + m_dmaf_high_address[1] = 0; + m_dmaf_high_address[2] = 0; + m_dmaf_high_address[3] = 0; m_floppy_motor_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(swtpc09_state::floppy_motor_callback),this)); m_floppy_motor_on = 0; @@ -845,6 +1019,7 @@ void swtpc09_state::init_swtpc09u() void swtpc09_state::init_swtpc09d3() { - m_via_ca1_input = 0; m_system_type = UNIFLEX_DMAF3; + // UniFLEX numbers sectors from 1. + m_hdc->set_sector_base(1); }