From e57098e49cf62d47b655c383f3f664f68ebb672f Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Fri, 16 May 2014 15:39:52 +0000 Subject: amigafdc: Add writing [O. Galibert] Formatting a floppy under a600 gets memory corruption then a guru meditation when reaching the point the system tries to write the directory structure. The fdc itself does not seem to be involved. I'd suspect the blitter, which afaik is used for the mfm expansion of the sector data. --- src/emu/machine/amigafdc.c | 269 ++++++++++++++++++++++++++++++++++----------- src/emu/machine/amigafdc.h | 9 ++ 2 files changed, 214 insertions(+), 64 deletions(-) (limited to 'src') diff --git a/src/emu/machine/amigafdc.c b/src/emu/machine/amigafdc.c index 334c2032a11..3b2e0668fe4 100644 --- a/src/emu/machine/amigafdc.c +++ b/src/emu/machine/amigafdc.c @@ -62,6 +62,11 @@ void amiga_fdc::device_reset() void amiga_fdc::dma_done() { amiga_state *state = machine().driver_data(); + if(dskbyt & 0x2000) { + dskbyt &= ~0x2000; + cur_live.pll.stop_writing(floppy, cur_live.tm); + } + dma_state = DMA_IDLE; state->custom_chip_w(REG_INTREQ, INTENA_SETCLR | INTENA_DSKBLK); } @@ -73,10 +78,28 @@ void amiga_fdc::dma_write(UINT16 value) dskpt += 2; dsklen--; + + if(dsklen & 0x3fff) + dma_state = DMA_RUNNING_BYTE_0; + else + dma_done(); +} + +UINT16 amiga_fdc::dma_read() +{ + amiga_state *state = machine().driver_data(); + UINT16 res = (*state->m_chip_ram_r)(state, dskpt); + + dskpt += 2; + dsklen--; + + // This loses the last word. So does the real hardware. if(dsklen & 0x3fff) dma_state = DMA_RUNNING_BYTE_0; else dma_done(); + + return res; } void amiga_fdc::live_start() @@ -95,6 +118,7 @@ void amiga_fdc::live_start() void amiga_fdc::checkpoint() { + cur_live.pll.commit(floppy, cur_live.tm); checkpoint_live = cur_live; } @@ -116,21 +140,33 @@ void amiga_fdc::live_sync() if(cur_live.tm > machine().time()) { rollback(); live_run(machine().time()); - } - if(cur_live.tm == machine().time()) { + cur_live.pll.commit(floppy, cur_live.tm); + + } else { + cur_live.pll.commit(floppy, 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) + if(cur_live.state == IDLE) { + cur_live.pll.stop_writing(floppy, cur_live.tm); cur_live.tm = attotime::never; + } } + cur_live.next_state = -1; checkpoint(); } } void amiga_fdc::live_abort() { + if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) { + rollback(); + live_run(machine().time()); + } + + cur_live.pll.stop_writing(floppy, cur_live.tm); cur_live.tm = attotime::never; cur_live.state = IDLE; cur_live.next_state = -1; @@ -146,35 +182,49 @@ void amiga_fdc::live_run(attotime limit) for(;;) { switch(cur_live.state) { case RUNNING: { - int bit = cur_live.pll.get_next_bit(cur_live.tm, floppy, limit); - if(bit < 0) - return; + if(!(dskbyt & 0x2000)) { + int bit = cur_live.pll.get_next_bit(cur_live.tm, floppy, limit); + if(bit < 0) + return; - cur_live.shift_reg = (cur_live.shift_reg << 1) | bit; - cur_live.bit_counter++; + cur_live.shift_reg = (cur_live.shift_reg << 1) | bit; + cur_live.bit_counter++; - if((adkcon & 0x0200) && !(cur_live.shift_reg & 0x80)) { - cur_live.bit_counter--; + if((adkcon & 0x0200) && !(cur_live.shift_reg & 0x80)) { + cur_live.bit_counter--; - // Avoid any risk of livelock - live_delay(RUNNING_SYNCPOINT); - return; - } + // Avoid any risk of livelock + live_delay(RUNNING_SYNCPOINT); + return; + } - if(cur_live.bit_counter > 8) - fatalerror("amiga_fdc::live_run - cur_live.bit_counter > 8\n"); + if(cur_live.bit_counter > 8) + fatalerror("amiga_fdc::live_run - cur_live.bit_counter > 8\n"); - if(cur_live.bit_counter == 8) { - live_delay(RUNNING_SYNCPOINT); - return; - } - if(dskbyt & 0x1000) { - if(cur_live.shift_reg != dsksync) { + if(cur_live.bit_counter == 8) { live_delay(RUNNING_SYNCPOINT); return; } + if(dskbyt & 0x1000) { + if(cur_live.shift_reg != dsksync) { + live_delay(RUNNING_SYNCPOINT); + return; + } + } else { + if(cur_live.shift_reg == dsksync) { + live_delay(RUNNING_SYNCPOINT); + return; + } + } } else { - if(cur_live.shift_reg == dsksync) { + int bit = (dma_state == DMA_RUNNING_BYTE_0 ? 15 : 7) - cur_live.bit_counter; + if(cur_live.pll.write_next_bit((dma_value >> bit) & 1, cur_live.tm, floppy, limit)) + return; + cur_live.bit_counter++; + if(cur_live.bit_counter > 8) + fatalerror("amiga_fdc::live_run - cur_live.bit_counter > 8\n"); + + if(cur_live.bit_counter == 8) { live_delay(RUNNING_SYNCPOINT); return; } @@ -183,50 +233,76 @@ void amiga_fdc::live_run(attotime limit) } case RUNNING_SYNCPOINT: { - if(cur_live.shift_reg == dsksync) { - if(adkcon & 0x0400) { - if(dma_state == DMA_WAIT_START) { - cur_live.bit_counter = 0; - - if(!(dsklen & 0x3fff)) - dma_done(); - else + if(!(dskbyt & 0x2000)) { + if(cur_live.shift_reg == dsksync) { + if(adkcon & 0x0400) { + if(dma_state == DMA_WAIT_START) { + cur_live.bit_counter = 0; + + if(!(dsklen & 0x3fff)) + dma_done(); + else if(dsklen & 0x4000) { + dskbyt |= 0x2000; + cur_live.bit_counter = 0; + dma_value = dma_read(); + + } else + dma_write(dsksync); + + } else if(dma_state != DMA_IDLE) { dma_write(dsksync); - - } else if(dma_state != DMA_IDLE) { - dma_write(dsksync); - cur_live.bit_counter = 0; - - } else if(cur_live.bit_counter != 8) - cur_live.bit_counter = 0; + cur_live.bit_counter = 0; + + } else if(cur_live.bit_counter != 8) + cur_live.bit_counter = 0; + } + dskbyt |= 0x1000; + state->custom_chip_w(REG_INTREQ, INTENA_SETCLR | INTENA_DSKSYN); + } else + dskbyt &= ~0x1000; + + if(cur_live.bit_counter == 8) { + dskbyt = (dskbyt & 0xff00) | 0x8000 | (cur_live.shift_reg & 0xff); + cur_live.bit_counter = 0; + + switch(dma_state) { + case DMA_IDLE: + case DMA_WAIT_START: + break; + + case DMA_RUNNING_BYTE_0: + dma_value = (cur_live.shift_reg & 0xff) << 8; + dma_state = DMA_RUNNING_BYTE_1; + break; + + case DMA_RUNNING_BYTE_1: { + dma_value |= cur_live.shift_reg & 0xff; + dma_write(dma_value); + break; + } + } } - dskbyt |= 0x1000; - state->custom_chip_w(REG_INTREQ, INTENA_SETCLR | INTENA_DSKSYN); - } else - dskbyt &= ~0x1000; - - if(cur_live.bit_counter == 8) { - dskbyt = (dskbyt & 0xff00) | 0x8000 | (cur_live.shift_reg & 0xff); + } else { + if(cur_live.bit_counter != 8) + fatalerror("amiga_fdc::live_run - cur_live.bit_counter != 8\n"); cur_live.bit_counter = 0; - + switch(dma_state) { case DMA_IDLE: case DMA_WAIT_START: break; - + case DMA_RUNNING_BYTE_0: - dma_value = (cur_live.shift_reg & 0xff) << 8; dma_state = DMA_RUNNING_BYTE_1; break; - + case DMA_RUNNING_BYTE_1: { - dma_value |= cur_live.shift_reg & 0xff; - dma_write(dma_value); + dma_value = dma_read(); break; } } } - + cur_live.state = RUNNING; checkpoint(); break; @@ -242,14 +318,33 @@ bool amiga_fdc::dma_enabled() void amiga_fdc::dma_check() { + bool was_writing = dskbyt & 0x2000; + dskbyt &= 0x9fff; if(dma_enabled()) { if(dma_state == IDLE) { dma_state = adkcon & 0x0400 ? DMA_WAIT_START : DMA_RUNNING_BYTE_0; - if(dma_state == DMA_RUNNING_BYTE_0 && !(dsklen & 0x3fff)) - dma_done(); + if(dma_state == DMA_RUNNING_BYTE_0) { + if(!(dsklen & 0x3fff)) + dma_done(); + else if(dsklen & 0x4000) { + dskbyt |= 0x2000; + cur_live.bit_counter = 0; + dma_value = dma_read(); + } + } + } else { + dskbyt |= 0x4000; + if(dsklen & 0x4000) + dskbyt |= 0x2000; } } else dma_state = IDLE; + + if(was_writing && !(dskbyt & 0x2000)) + cur_live.pll.stop_writing(floppy, cur_live.tm); + if(!was_writing && (dskbyt & 0x2000)) + cur_live.pll.start_writing(cur_live.tm); + } void amiga_fdc::adkcon_set(UINT16 data) @@ -271,11 +366,6 @@ void amiga_fdc::dsklen_w(UINT16 data) dsklen = pre_dsklen = data; dma_check(); - dskbyt = dskbyt & 0x9fff; - if(data & 0x4000) - dskbyt |= 0x2000; - if(dma_state != DMA_IDLE) - dskbyt |= 0x4000; } else pre_dsklen = data; live_run(); @@ -317,9 +407,6 @@ void amiga_fdc::dmacon_set(UINT16 data) live_sync(); dmacon = data; dma_check(); - dskbyt = dskbyt & 0xbfff; - if(dma_state != DMA_IDLE) - dskbyt |= 0x4000; live_run(); } @@ -384,7 +471,7 @@ WRITE8_MEMBER( amiga_fdc::ciaaprb_w ) floppy->dir_w((data >> 1) & 1); floppy->stp_w(data & 1); floppy->mon_w((data >> 7) & 1); - output_set_value("fdc_led",data & 0x80); // LED directly connected to FDC motor + output_set_value("fdc_led", data & 0x80); // LED directly connected to FDC motor } if(floppy) { @@ -405,7 +492,7 @@ UINT8 amiga_fdc::ciaapra_r() ret &= ~0x20; if(!floppy->trk00_r()) ret &= ~0x10; - if(!floppy->wpt_r()) + if(floppy->wpt_r()) ret &= ~0x08; if(!floppy->dskchg_r()) ret &= ~0x04; @@ -513,3 +600,57 @@ int amiga_fdc::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, at return bit; } + +void amiga_fdc::pll_t::start_writing(attotime tm) +{ + write_start_time = tm; + write_position = 0; +} + +void amiga_fdc::pll_t::stop_writing(floppy_image_device *floppy, attotime tm) +{ + commit(floppy, tm); + write_start_time = attotime::never; +} + +bool amiga_fdc::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; + } + + for(;;) { + attotime etime = ctime+delays[slot]; + if(etime > limit) + return true; + UINT16 pre_counter = counter; + counter += increment; + if(bit && !(pre_counter & 0x400) && (counter & 0x400)) + if(write_position < ARRAY_LENGTH(write_buffer)) + write_buffer[write_position++] = etime; + slot++; + tm = etime; + if(counter & 0x800) + break; + } + + counter &= 0x7ff; + + ctime = tm; + slot = 0; + + return false; +} + + +void amiga_fdc::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; +} diff --git a/src/emu/machine/amigafdc.h b/src/emu/machine/amigafdc.h index d8b0366105d..c2e71a269c1 100644 --- a/src/emu/machine/amigafdc.h +++ b/src/emu/machine/amigafdc.h @@ -62,9 +62,17 @@ private: attotime delays[38]; + attotime write_start_time; + attotime write_buffer[32]; + int write_position; + 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 live_info { @@ -95,6 +103,7 @@ private: void dma_check(); void dma_done(); void dma_write(UINT16 value); + UINT16 dma_read(); void live_start(); void checkpoint(); -- cgit v1.2.3