summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/amigafdc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/amigafdc.cpp')
-rw-r--r--src/devices/machine/amigafdc.cpp661
1 files changed, 0 insertions, 661 deletions
diff --git a/src/devices/machine/amigafdc.cpp b/src/devices/machine/amigafdc.cpp
deleted file mode 100644
index 69ec9066f87..00000000000
--- a/src/devices/machine/amigafdc.cpp
+++ /dev/null
@@ -1,661 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Olivier Galibert
-/***************************************************************************
-
- Amiga floppy disk controller emulation
-
-***************************************************************************/
-
-
-#include "emu.h"
-#include "formats/ami_dsk.h"
-#include "amigafdc.h"
-
-DEFINE_DEVICE_TYPE(AMIGA_FDC, amiga_fdc_device, "amiga_fdc", "Amiga FDC")
-
-FLOPPY_FORMATS_MEMBER( amiga_fdc_device::floppy_formats )
- FLOPPY_ADF_FORMAT
-FLOPPY_FORMATS_END
-
-amiga_fdc_device::amiga_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
- device_t(mconfig, AMIGA_FDC, tag, owner, clock),
- m_write_index(*this),
- m_read_dma(*this),
- m_write_dma(*this),
- m_write_dskblk(*this),
- m_write_dsksyn(*this),
- m_leds(*this, "led%u", 1U),
- floppy(nullptr), t_gen(nullptr), dsklen(0), pre_dsklen(0), dsksync(0), dskbyt(0), adkcon(0), dmacon(0), dskpt(0), dma_value(0), dma_state(0)
-{
-}
-
-void amiga_fdc_device::device_start()
-{
- m_write_index.resolve_safe();
- m_read_dma.resolve_safe(0);
- m_write_dma.resolve_safe();
- m_write_dskblk.resolve_safe();
- m_write_dsksyn.resolve_safe();
- m_leds.resolve();
-
- static char const *const names[] = { "0", "1", "2", "3" };
- for(int i=0; i != 4; i++) {
- floppy_connector *con = subdevice<floppy_connector>(names[i]);
- if(con)
- floppy_devices[i] = con->get_device();
- else
- floppy_devices[i] = nullptr;
- }
-
- floppy = nullptr;
-
- t_gen = timer_alloc(0);
-}
-
-
-void amiga_fdc_device::device_reset()
-{
- floppy = nullptr;
- dsklen = 0x4000;
- dsksync = 0x4489;
- adkcon = 0;
- dmacon = 0;
- dskpt = 0;
- dskbyt = 0;
- pre_dsklen = 0x4000;
- dma_value = 0;
- dma_state = DMA_IDLE;
-
- live_abort();
-}
-
-void amiga_fdc_device::dma_done()
-{
- if(dskbyt & 0x2000) {
- dskbyt &= ~0x2000;
- cur_live.pll.stop_writing(floppy, cur_live.tm);
- }
-
- dma_state = DMA_IDLE;
- m_write_dskblk(1);
-}
-
-void amiga_fdc_device::dma_write(uint16_t value)
-{
- m_write_dma(dskpt, value, 0xffff);
-
- dskpt += 2;
- dsklen--;
-
- if(dsklen & 0x3fff)
- dma_state = DMA_RUNNING_BYTE_0;
- else
- dma_done();
-}
-
-uint16_t amiga_fdc_device::dma_read()
-{
- uint16_t res = m_read_dma(dskpt, 0xffff);
-
- 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_device::live_start()
-{
- cur_live.tm = machine().time();
- cur_live.state = RUNNING;
- cur_live.next_state = -1;
- cur_live.shift_reg = 0;
- cur_live.bit_counter = 0;
- cur_live.pll.reset(cur_live.tm);
- cur_live.pll.set_clock(clocks_to_attotime(1));
- checkpoint_live = cur_live;
-
- live_run();
-}
-
-void amiga_fdc_device::checkpoint()
-{
- cur_live.pll.commit(floppy, cur_live.tm);
- checkpoint_live = cur_live;
-}
-
-void amiga_fdc_device::rollback()
-{
- cur_live = checkpoint_live;
-}
-
-void amiga_fdc_device::live_delay(int state)
-{
- cur_live.next_state = state;
- if(cur_live.tm != machine().time())
- t_gen->adjust(cur_live.tm - machine().time());
-}
-
-void amiga_fdc_device::live_sync()
-{
- if(!cur_live.tm.is_never()) {
- if(cur_live.tm > machine().time()) {
- rollback();
- live_run(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) {
- cur_live.pll.stop_writing(floppy, cur_live.tm);
- cur_live.tm = attotime::never;
- }
- }
- cur_live.next_state = -1;
- checkpoint();
- }
-}
-
-void amiga_fdc_device::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;
-}
-
-void amiga_fdc_device::live_run(const attotime &limit)
-{
- if(cur_live.state == IDLE || cur_live.next_state != -1)
- return;
-
- for(;;) {
- switch(cur_live.state) {
- case RUNNING: {
- 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++;
-
- if((adkcon & 0x0200) && !(cur_live.shift_reg & 0x80)) {
- cur_live.bit_counter--;
-
- // Avoid any risk of livelock
- live_delay(RUNNING_SYNCPOINT);
- return;
- }
-
- if(cur_live.bit_counter > 8)
- fatalerror("amiga_fdc_device::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) {
- live_delay(RUNNING_SYNCPOINT);
- return;
- }
- } else {
- if(cur_live.shift_reg == dsksync) {
- live_delay(RUNNING_SYNCPOINT);
- return;
- }
- }
- } else {
- 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_device::live_run - cur_live.bit_counter > 8\n");
-
- if(cur_live.bit_counter == 8) {
- live_delay(RUNNING_SYNCPOINT);
- return;
- }
- }
- break;
- }
-
- case RUNNING_SYNCPOINT: {
- 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);
- cur_live.bit_counter = 0;
-
- } else if(cur_live.bit_counter != 8)
- cur_live.bit_counter = 0;
- }
- dskbyt |= 0x1000;
- m_write_dsksyn(1);
- } 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;
- }
- }
- }
- } else {
- if(cur_live.bit_counter != 8)
- fatalerror("amiga_fdc_device::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_state = DMA_RUNNING_BYTE_1;
- break;
-
- case DMA_RUNNING_BYTE_1: {
- dma_value = dma_read();
- break;
- }
- }
- }
-
- cur_live.state = RUNNING;
- checkpoint();
- break;
- }
- }
- }
-}
-
-bool amiga_fdc_device::dma_enabled()
-{
- return (dsklen & 0x8000) && ((dmacon & 0x0210) == 0x0210);
-}
-
-void amiga_fdc_device::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) {
- 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_device::adkcon_set(uint16_t data)
-{
- live_sync();
- adkcon = data;
- live_run();
-}
-
-uint16_t amiga_fdc_device::adkcon_r(void)
-{
- return adkcon;
-}
-
-void amiga_fdc_device::dsklen_w(uint16_t data)
-{
- live_sync();
- if(!(data & 0x8000) || (data == pre_dsklen)) {
- dsklen = pre_dsklen = data;
- dma_check();
-
- } else
- pre_dsklen = data;
- live_run();
-}
-
-void amiga_fdc_device::dskpth_w(uint16_t data)
-{
- live_sync();
- dskpt = (dskpt & 0xffff) | (data << 16);
- live_run();
-}
-
-void amiga_fdc_device::dskptl_w(uint16_t data)
-{
- live_sync();
- dskpt = (dskpt & 0xffff0000) | data;
- live_run();
-}
-
-uint16_t amiga_fdc_device::dskpth_r()
-{
- return dskpt >> 16;
-}
-
-uint16_t amiga_fdc_device::dskptl_r()
-{
- return dskpt;
-}
-
-void amiga_fdc_device::dsksync_w(uint16_t data)
-{
- live_sync();
- dsksync = data;
- live_run();
-}
-
-void amiga_fdc_device::dmacon_set(uint16_t data)
-{
- live_sync();
- dmacon = data;
- dma_check();
- live_run();
-}
-
-uint16_t amiga_fdc_device::dskbytr_r()
-{
- uint16_t res = dskbyt;
- dskbyt &= 0x7fff;
- return res;
-}
-
-void amiga_fdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- live_sync();
- live_run();
-}
-
-void amiga_fdc_device::setup_leds()
-{
- if(floppy) {
- int drive =
- floppy == floppy_devices[0] ? 0 :
- floppy == floppy_devices[1] ? 1 :
- floppy == floppy_devices[2] ? 2 :
- 3;
-
- machine().output().set_value("drive_0_led", drive == 0);
- machine().output().set_value("drive_1_led", drive == 1);
- machine().output().set_value("drive_2_led", drive == 2);
- machine().output().set_value("drive_3_led", drive == 3);
-
- m_leds[0] = drive == 0 ? 1 : 0; // update internal drive led
- m_leds[1] = drive == 1 ? 1 : 0; // update external drive led
- }
-}
-
-WRITE8_MEMBER( amiga_fdc_device::ciaaprb_w )
-{
- floppy_image_device *old_floppy = floppy;
-
- live_sync();
-
- if(!(data & 0x08))
- floppy = floppy_devices[0];
- else if(!(data & 0x10))
- floppy = floppy_devices[1];
- else if(!(data & 0x20))
- floppy = floppy_devices[2];
- else if(!(data & 0x40))
- floppy = floppy_devices[3];
- else
- floppy = nullptr;
-
- if(old_floppy != floppy) {
- if(old_floppy)
- old_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb());
- if(floppy)
- floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(&amiga_fdc_device::index_callback, this));
- }
-
- if(floppy) {
- floppy->ss_w(!((data >> 2) & 1));
- floppy->dir_w((data >> 1) & 1);
- floppy->stp_w(data & 1);
- floppy->mon_w((data >> 7) & 1);
- machine().output().set_value("fdc_led", data & 0x80); // LED directly connected to FDC motor
- }
-
- if(floppy) {
- if(cur_live.state == IDLE)
- live_start();
- } else
- live_abort();
-
- setup_leds();
- live_run();
-}
-
-uint8_t amiga_fdc_device::ciaapra_r()
-{
- uint8_t ret = 0x3c;
- if(floppy) {
- //if(!floppy->ready_r()) fixit: seems to not work well with multiple disk drives
- ret &= ~0x20;
- if(!floppy->trk00_r())
- ret &= ~0x10;
- if(floppy->wpt_r())
- ret &= ~0x08;
- if(!floppy->dskchg_r())
- ret &= ~0x04;
- }
-
- return ret;
-}
-
-void amiga_fdc_device::index_callback(floppy_image_device *floppy, int state)
-{
- /* Issue a index pulse when a disk revolution completes */
- m_write_index(!state);
-}
-
-void amiga_fdc_device::pll_t::set_clock(const attotime &period)
-{
- for(int i=0; i<38; i++)
- delays[i] = period*(i+1);
-}
-
-void amiga_fdc_device::pll_t::reset(const attotime &when)
-{
- counter = 0;
- increment = 146;
- transition_time = 0xffff;
- history = 0x80;
- slot = 0;
- ctime = when;
- phase_add = 0x00;
- phase_sub = 0x00;
- freq_add = 0x00;
- freq_sub = 0x00;
-}
-
-int amiga_fdc_device::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit)
-{
- attotime when = floppy ? floppy->get_next_transition(ctime) : attotime::never;
-
- for(;;) {
- attotime etime = ctime+delays[slot];
- if(etime > limit)
- return -1;
- if(transition_time == 0xffff && !when.is_never() && etime >= when)
- transition_time = counter;
- if(slot < 8) {
- uint8_t mask = 1 << slot;
- if(phase_add & mask)
- counter += 258;
- else if(phase_sub & mask)
- counter += 34;
- else
- counter += increment;
-
- if((freq_add & mask) && increment < 159)
- increment++;
- else if((freq_sub & mask) && increment > 134)
- increment--;
- } else
- counter += increment;
-
- slot++;
- tm = etime;
- if(counter & 0x800)
- break;
- }
-
- int bit = transition_time != 0xffff;
-
- if(transition_time != 0xffff) {
- static uint8_t const pha[8] = { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 };
- static uint8_t const phs[8] = { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf };
- static uint8_t const freqa[4][8] = {
- { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 },
- { 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 },
- { 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 }
- };
- static uint8_t const freqs[4][8] = {
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 },
- { 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 },
- { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf },
- };
-
- int cslot = transition_time >> 8;
- phase_add = pha[cslot];
- phase_sub = phs[cslot];
- int way = transition_time & 0x400 ? 1 : 0;
- if(history & 0x80)
- history = way ? 0x80 : 0x83;
- else if(history & 0x40)
- history = way ? history & 2 : (history & 2) | 1;
- freq_add = freqa[history & 3][cslot];
- freq_sub = freqs[history & 3][cslot];
- history = way ? (history >> 1) | 2 : history >> 1;
-
- } else
- phase_add = phase_sub = freq_add = freq_sub = 0;
-
- counter &= 0x7ff;
-
- ctime = tm;
- transition_time = 0xffff;
- slot = 0;
-
- return bit;
-}
-
-void amiga_fdc_device::pll_t::start_writing(const attotime & tm)
-{
- write_start_time = tm;
- write_position = 0;
-}
-
-void amiga_fdc_device::pll_t::stop_writing(floppy_image_device *floppy, const attotime &tm)
-{
- commit(floppy, tm);
- write_start_time = attotime::never;
-}
-
-bool amiga_fdc_device::pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const 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_t 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_device::pll_t::commit(floppy_image_device *floppy, const 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;
-}