amigafdc: Upgrade [O. Galibert]

This commit is contained in:
Olivier Galibert 2011-11-01 11:14:16 +00:00
parent 974ea3d59e
commit c965e4ad27
11 changed files with 590 additions and 30 deletions

View File

@ -164,6 +164,7 @@ EMUMACHINEOBJS = \
$(EMUMACHINE)/adc1213x.o \
$(EMUMACHINE)/am53cf96.o \
$(EMUMACHINE)/am8530h.o \
$(EMUMACHINE)/amigafdc.o \
$(EMUMACHINE)/at28c16.o \
$(EMUMACHINE)/cdp1852.o \
$(EMUMACHINE)/cdp1871.o \

View File

@ -269,6 +269,7 @@ void floppy_image_device::stp_w(int state)
} else {
if ( cyl < tracks-1 ) cyl++;
}
/* Update disk detection if applicable */
if (exists())
{
@ -286,14 +287,6 @@ int floppy_image_device::find_position(int position, const UINT32 *buf, int buf_
step >>= 1;
for(;;) {
#if 0
fprintf(stderr, "%09d - %09d / %09d -- %6d %6d %6d\n",
position,
spos < 0 ? 0 : spos >= buf_size ? 200000000 :buf[spos] & floppy_image::TIME_MASK,
spos < 0 ? 0 : spos >= buf_size-1 ? 200000000 : buf[spos+1] & floppy_image::TIME_MASK,
spos, step, buf_size);
#endif
if(spos >= buf_size || (spos > 0 && (buf[spos] & floppy_image::TIME_MASK) > position)) {
spos -= step;
step >>= 1;
@ -328,7 +321,6 @@ attotime floppy_image_device::get_next_transition(attotime from_when)
const UINT32 *buf = image->get_buffer(cyl, ss);
int index = find_position(position, buf, cells);
// fprintf(stderr, "position=%9d, index=%d\n", position, index);
if(index == -1)
return attotime::never;
@ -340,6 +332,5 @@ attotime floppy_image_device::get_next_transition(attotime from_when)
else
next_position = 200000000 + (buf[1] & floppy_image::TIME_MASK);
// printf("next_pos=%d, delta=%d\n", next_position, next_position-position);
return base + attotime::from_nsec(next_position*(300/rpm));
}

View File

@ -0,0 +1,454 @@
/****************************************************f***********************
Amiga floppy disk controller emulation
***************************************************************************/
#include "emu.h"
#include "includes/amiga.h"
#include "formats/ami_dsk.h"
#include "formats/hxcmfm_dsk.h"
#include "formats/ipf_dsk.h"
#include "formats/mfi_dsk.h"
#include "amigafdc.h"
#include "machine/6526cia.h"
const device_type AMIGA_FDC = &device_creator<amiga_fdc>;
const floppy_format_type amiga_fdc::floppy_formats[] = {
FLOPPY_ADF_FORMAT, FLOPPY_MFM_FORMAT, FLOPPY_IPF_FORMAT, FLOPPY_MFI_FORMAT,
NULL
};
amiga_fdc::amiga_fdc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, AMIGA_FDC, "Amiga FDC", tag, owner, clock)
{
}
void amiga_fdc::device_start()
{
floppy_devices[0] = machine().device<floppy_image_device>("fd0");
floppy_devices[1] = machine().device<floppy_image_device>("fd1");
floppy_devices[2] = machine().device<floppy_image_device>("fd2");
floppy_devices[3] = machine().device<floppy_image_device>("fd3");
floppy = 0;
t_gen = timer_alloc(0);
}
void amiga_fdc::device_reset()
{
floppy = 0;
dsklen = 0x4000;
dsksync = 0x4489;
adkcon = 0;
dmacon = 0;
dskpt = 0;
dsklen = 0x4000;
pre_dsklen = 0x4000;
dma_value = 0;
dma_state = DMA_IDLE;
live_abort();
}
void amiga_fdc::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::checkpoint()
{
checkpoint_live = cur_live;
}
void amiga_fdc::rollback()
{
cur_live = checkpoint_live;
}
void amiga_fdc::live_delay(int state)
{
cur_live.next_state = state;
t_gen->adjust(cur_live.tm - machine().time());
}
void amiga_fdc::live_sync()
{
if(!cur_live.tm.is_never()) {
if(cur_live.tm > machine().time()) {
rollback();
live_run(machine().time());
} else {
if(cur_live.next_state != -1)
cur_live.state = cur_live.next_state;
if(cur_live.state == IDLE)
cur_live.tm = attotime::never;
}
cur_live.next_state = -1;
checkpoint();
}
}
void amiga_fdc::live_abort()
{
cur_live.tm = attotime::never;
cur_live.state = IDLE;
cur_live.next_state = -1;
}
void amiga_fdc::live_run(attotime limit)
{
if(cur_live.state == IDLE || cur_live.next_state != -1)
return;
for(;;) {
switch(cur_live.state) {
case RUNNING: {
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--;
if(cur_live.bit_counter == 8) {
live_delay(RUNNING_SYNCPOINT);
return;
}
if(dskbyt & 0x0400) {
if(cur_live.shift_reg != dsksync) {
live_delay(RUNNING_SYNCPOINT);
return;
}
} else {
if(cur_live.shift_reg == dsksync) {
live_delay(RUNNING_SYNCPOINT);
return;
}
}
break;
}
case RUNNING_SYNCPOINT: {
if(cur_live.shift_reg == dsksync) {
if(adkcon & 0x0400) {
if(dma_state == DMA_WAIT_START)
dma_state = DMA_RUNNING_BYTE_0;
cur_live.bit_counter = 0;
}
dskbyt |= 0x0400;
address_space *space = machine().device("maincpu")->memory().space(AS_PROGRAM);
amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKSYN, 0xffff);
} else
dskbyt &= ~0x0400;
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;
amiga_state *state = machine().driver_data<amiga_state>();
(*state->m_chip_ram_w)(state, dskpt, dma_value);
dskpt += 2;
dsklen--;
if(dsklen & 0x3fff)
dma_state = DMA_RUNNING_BYTE_0;
else {
dma_state = DMA_IDLE;
address_space *space = machine().device("maincpu")->memory().space(AS_PROGRAM);
amiga_custom_w(space, REG_INTREQ, 0x8000 | INTENA_DSKBLK, 0xffff);
}
break;
}
}
}
cur_live.state = RUNNING;
checkpoint();
break;
}
}
}
}
bool amiga_fdc::dma_enabled()
{
return (dsklen & 0x8000) && ((dmacon & 0x0210) == 0x0210);
}
void amiga_fdc::dma_check()
{
if(dma_enabled() && (dsklen & 0x3fff)) {
if(dma_state == IDLE)
dma_state = adkcon & 0x0400 ? DMA_WAIT_START : DMA_RUNNING_BYTE_0;
} else
dma_state = IDLE;
}
void amiga_fdc::adkcon_set(UINT16 data)
{
live_sync();
adkcon = data;
}
void amiga_fdc::dsklen_w(UINT16 data)
{
live_sync();
if(!(data & 0x8000) || (data == pre_dsklen)) {
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;
}
void amiga_fdc::dskpth_w(UINT16 data)
{
live_sync();
dskpt = (dskpt & 0xffff) | (data << 16);
}
void amiga_fdc::dskptl_w(UINT16 data)
{
live_sync();
dskpt = (dskpt & 0xffff0000) | data;
}
UINT16 amiga_fdc::dskpth_r()
{
return dskpt >> 16;
}
UINT16 amiga_fdc::dskptl_r()
{
return dskpt;
}
void amiga_fdc::dsksync_w(UINT16 data)
{
live_sync();
dsksync = data;
}
void amiga_fdc::dmacon_set(UINT16 data)
{
live_sync();
dmacon = data;
dma_check();
dskbyt = dskbyt & 0xbfff;
if(dma_state != DMA_IDLE)
dskbyt |= 0x4000;
}
UINT16 amiga_fdc::dskbytr_r()
{
return dskbyt;
}
void amiga_fdc::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
live_sync();
live_run();
}
void amiga_fdc::setup_leds()
{
if(floppy) {
int drive =
floppy == floppy_devices[0] ? 0 :
floppy == floppy_devices[1] ? 1 :
floppy == floppy_devices[2] ? 2 :
3;
output_set_value("drive_0_led", drive == 0);
output_set_value("drive_1_led", drive == 1);
output_set_value("drive_2_led", drive == 2);
output_set_value("drive_3_led", drive == 3);
set_led_status(machine(), 1, drive == 0); /* update internal drive led */
set_led_status(machine(), 2, drive == 1); /* update external drive led */
}
}
WRITE8_MEMBER( amiga_fdc::ciaaprb_w )
{
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 = 0;
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);
}
if(floppy) {
if(cur_live.state == IDLE)
live_start();
} else
live_abort();
setup_leds();
}
UINT8 amiga_fdc::ciaapra_r()
{
UINT8 ret = 0x3c;
if(floppy) {
// fixit
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::index_callback(floppy_image_device *floppy, int state)
{
/* Issue a index pulse when a disk revolution completes */
device_t *cia = machine().device("cia_1");
mos6526_flag_w(cia, state);
}
void amiga_fdc::pll_t::set_clock(attotime period)
{
for(int i=0; i<38; i++)
delays[i] = period*(i+1);
}
void amiga_fdc::pll_t::reset(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::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, 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 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 const UINT8 pha[8] = { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 };
static const UINT8 phs[8] = { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf };
static const UINT8 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 const UINT8 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;
}

View File

@ -0,0 +1,103 @@
#ifndef AMIGAFDC_H
#define AMIGAFDC_H
#include "emu.h"
#include "imagedev/floppy.h"
#define MCFG_AMIGA_FDC_ADD(_tag, _clock) \
MCFG_DEVICE_ADD(_tag, AMIGA_FDC, _clock)
class amiga_fdc : public device_t {
public:
amiga_fdc(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
DECLARE_WRITE8_MEMBER(ciaaprb_w);
UINT8 ciaapra_r();
UINT16 dskbytr_r();
UINT16 dskpth_r();
UINT16 dskptl_r();
void dsksync_w(UINT16 data);
void dskpth_w(UINT16 data);
void dskptl_w(UINT16 data);
void dsklen_w(UINT16 data);
void adkcon_set(UINT16 data);
void dmacon_set(UINT16 data);
static const floppy_format_type floppy_formats[];
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:
// Running states
enum {
IDLE,
RUNNING,
RUNNING_SYNCPOINT
};
// DMA states
enum {
DMA_IDLE,
DMA_WAIT_START,
DMA_RUNNING_BYTE_0,
DMA_RUNNING_BYTE_1
};
struct pll_t {
UINT16 counter;
UINT16 increment;
UINT16 transition_time;
UINT8 history;
UINT8 slot;
UINT8 phase_add, phase_sub, freq_add, freq_sub;
attotime ctime;
attotime delays[38];
void set_clock(attotime period);
void reset(attotime when);
int get_next_bit(attotime &tm, floppy_image_device *floppy, attotime limit);
};
struct live_info {
attotime tm;
int state, next_state;
UINT16 shift_reg;
int bit_counter;
pll_t pll;
};
floppy_image_device *floppy;
floppy_image_device *floppy_devices[4];
live_info cur_live, checkpoint_live;
emu_timer *t_gen;
UINT16 dsklen, pre_dsklen, dsksync, dskbyt, adkcon, dmacon;
UINT32 dskpt;
UINT16 dma_value;
int dma_state;
void setup_leds();
void index_callback(floppy_image_device *floppy, int state);
bool dma_enabled();
void dma_check();
void live_start();
void checkpoint();
void rollback();
void live_delay(int state);
void live_sync();
void live_abort();
void live_run(attotime limit = attotime::never);
};
extern const device_type AMIGA_FDC;
#endif /* AMIGAFDC_H */

View File

@ -685,7 +685,7 @@ static void alg_init(running_machine &machine)
{
ANGUS_CHIP_RAM_MASK,
NULL, NULL, alg_potgo_w,
NULL, NULL, serial_w,
serial_w,
vsync_callback,
NULL,

View File

@ -793,7 +793,7 @@ static void arcadia_init(running_machine &machine)
{
ANGUS_CHIP_RAM_MASK,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL,
NULL, arcadia_reset_coins,
NULL,
0

View File

@ -834,7 +834,7 @@ static DRIVER_INIT( cd32 )
{
AGA_CHIP_RAM_MASK,
NULL, NULL, cd32_potgo_w,
NULL, NULL, NULL,
NULL,
NULL, NULL,
NULL,
FLAGS_AGA_CHIPSET
@ -1454,7 +1454,7 @@ static DRIVER_INIT( odeontw2 )
{
AGA_CHIP_RAM_MASK,
NULL, NULL, cd32_potgo_w,
NULL, NULL, serial_w,
serial_w,
NULL, NULL,
NULL,
FLAGS_AGA_CHIPSET

View File

@ -433,7 +433,7 @@ static DRIVER_INIT(mquake)
{
ANGUS_CHIP_RAM_MASK,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL,
NULL, NULL,
NULL,
0

View File

@ -390,7 +390,7 @@ static DRIVER_INIT( upscope )
{
ANGUS_CHIP_RAM_MASK,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL,
NULL, upscope_reset,
NULL,
0

View File

@ -97,7 +97,7 @@ Ernesto Corvi & Mariusz Wojcieszek
#define REG_BLTBDAT (0x072/2) /* W A Blitter source B data reglster */
#define REG_BLTADAT (0x074/2) /* W A Blitter source A data register */
#define REG_DENISEID (0x07C/2) /* R D Denise ID: OCS = 0xFF, ECS = 0xFC, AGA = 0xF8 */
#define REG_DSRSYNC (0x07E/2) /* W P Disk sync pattern register for disk read */
#define REG_DSKSYNC (0x07E/2) /* W P Disk sync pattern register for disk read */
#define REG_COP1LCH (0x080/2) /* W A Coprocessor first location register (high 3 bits) */
#define REG_COP1LCL (0x082/2) /* W A Coprocessor first location register (low 15 bits) */
#define REG_COP2LCH (0x084/2) /* W A Coprocessor second location register (high 3 bits) */
@ -329,9 +329,6 @@ struct _amiga_machine_interface
UINT16 (*joy1dat_r)(running_machine &machine);
void (*potgo_w)(running_machine &machine, UINT16 data);
UINT16 (*dskbytr_r)(running_machine &machine);
void (*dsklen_w)(running_machine &machine, UINT16 data);
void (*serdat_w)(running_machine &machine, UINT16 data);
void (*scanline0_callback)(running_machine &machine);

View File

@ -12,7 +12,7 @@
#include "includes/amiga.h"
#include "cpu/m68000/m68000.h"
#include "machine/6526cia.h"
#include "machine/amigafdc.h"
/*************************************
*
@ -1181,9 +1181,6 @@ READ16_HANDLER( amiga_custom_r )
return (*state->m_intf->joy1dat_r)(space->machine());
return input_port_read_safe(space->machine(), "JOY1DAT", 0xffff);
case REG_ADKCONR:
return CUSTOM_REG(REG_ADKCON);
case REG_POTGOR:
return input_port_read_safe(space->machine(), "POTGO", 0x5500);
@ -1194,9 +1191,7 @@ READ16_HANDLER( amiga_custom_r )
return input_port_read_safe(space->machine(), "POT1DAT", 0x0000);
case REG_DSKBYTR:
if (state->m_intf->dskbytr_r != NULL)
return (*state->m_intf->dskbytr_r)(space->machine());
return 0x0000;
return space->machine().device<amiga_fdc>("fdc")->dskbytr_r();
case REG_INTENAR:
return CUSTOM_REG(REG_INTENA);
@ -1219,6 +1214,12 @@ READ16_HANDLER( amiga_custom_r )
case REG_DENISEID:
return CUSTOM_REG(REG_DENISEID);
case REG_DSKPTH:
return space->machine().device<amiga_fdc>("fdc")->dskpth_r();
case REG_DSKPTL:
return space->machine().device<amiga_fdc>("fdc")->dskptl_r();
}
if (LOG_CUSTOM)
@ -1267,9 +1268,20 @@ WRITE16_HANDLER( amiga_custom_w )
/* read-only registers */
break;
case REG_DSKSYNC:
space->machine().device<amiga_fdc>("fdc")->dsksync_w(data);
break;
case REG_DSKPTH:
space->machine().device<amiga_fdc>("fdc")->dskpth_w(data);
break;
case REG_DSKPTL:
space->machine().device<amiga_fdc>("fdc")->dskptl_w(data);
break;
case REG_DSKLEN:
if (state->m_intf->dsklen_w != NULL)
(*state->m_intf->dsklen_w)(space->machine(), data);
space->machine().device<amiga_fdc>("fdc")->dsklen_w(data);
break;
case REG_POTGO:
@ -1372,7 +1384,8 @@ WRITE16_HANDLER( amiga_custom_w )
/* bits BBUSY (14) and BZERO (13) are read-only */
data &= 0x9fff;
data = (data & 0x8000) ? (CUSTOM_REG(offset) | (data & 0x7fff)) : (CUSTOM_REG(offset) & ~(data & 0x7fff));
space->machine().device<amiga_fdc>("fdc")->dmacon_set(data);
/* if 'blitter-nasty' has been turned on and we have a blit pending, reschedule it */
if ( ( data & 0x400 ) && ( CUSTOM_REG(REG_DMACON) & 0x4000 ) )
state->m_blitter_timer->adjust( downcast<cpu_device *>(&space->device())->cycles_to_attotime( BLITTER_NASTY_DELAY ));
@ -1413,6 +1426,7 @@ WRITE16_HANDLER( amiga_custom_w )
case REG_ADKCON:
amiga_audio_update(state->m_sound_device);
data = (data & 0x8000) ? (CUSTOM_REG(offset) | (data & 0x7fff)) : (CUSTOM_REG(offset) & ~(data & 0x7fff));
space->machine().device<amiga_fdc>("fdc")->adkcon_set(data);
break;
case REG_AUD0LCL: case REG_AUD0LCH: case REG_AUD0LEN: case REG_AUD0PER: case REG_AUD0VOL: