summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/emu/machine/amigafdc.c269
-rw-r--r--src/emu/machine/amigafdc.h9
2 files changed, 214 insertions, 64 deletions
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<amiga_state>();
+ 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<amiga_state>();
+ 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();