summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/lib.lua2
-rw-r--r--src/devices/machine/i8271.c2620
-rw-r--r--src/devices/machine/i8271.h391
-rw-r--r--src/lib/formats/atom_dsk.c31
-rw-r--r--src/lib/formats/atom_dsk.h22
-rw-r--r--src/mess/drivers/atom.c43
-rw-r--r--src/mess/drivers/bbc.c21
-rw-r--r--src/mess/drivers/imds2.c48
-rw-r--r--src/mess/includes/atom.h6
-rw-r--r--src/mess/includes/bbc.h1
-rw-r--r--src/mess/includes/imds2.h5
-rw-r--r--src/mess/machine/bbc.c6
12 files changed, 1787 insertions, 1409 deletions
diff --git a/scripts/src/lib.lua b/scripts/src/lib.lua
index 96e55653969..c8b2057d187 100644
--- a/scripts/src/lib.lua
+++ b/scripts/src/lib.lua
@@ -165,6 +165,8 @@ project "formats"
MAME_DIR .. "src/lib/formats/asst128_dsk.h",
MAME_DIR .. "src/lib/formats/atari_dsk.c",
MAME_DIR .. "src/lib/formats/atari_dsk.h",
+ MAME_DIR .. "src/lib/formats/atom_dsk.c",
+ MAME_DIR .. "src/lib/formats/atom_dsk.h",
MAME_DIR .. "src/lib/formats/atom_tap.c",
MAME_DIR .. "src/lib/formats/atom_tap.h",
MAME_DIR .. "src/lib/formats/bbc_dsk.c",
diff --git a/src/devices/machine/i8271.c b/src/devices/machine/i8271.c
index 08e5944f4fc..0f8f48dda3c 100644
--- a/src/devices/machine/i8271.c
+++ b/src/devices/machine/i8271.c
@@ -1,1510 +1,1696 @@
// license:BSD-3-Clause
-// copyright-holders:Kevin Thacker
-/* Intel 8271 Floppy Disc Controller */
-/* used in BBC Micro B,Acorn Atom */
-/* Jun 2000. Kev Thacker */
+// copyright-holders:Carl,Olivier Galibert
-/* TODO:
-
- - Scan commands
- - Check the commands work properly using a BBC disc copier program
- - check if 0 is specified as number of sectors, how many sectors
- is actually transfered
- - deleted data functions (error if data finds deleted data?)
-*/
-
-
-#include "emu.h"
#include "i8271.h"
-/* data request */
-#define I8271_FLAGS_DATA_REQUEST 0x01
-/* data direction. If 0x02, then it is from fdc to cpu, else
-it is from cpu to fdc */
-#define I8271_FLAGS_DATA_DIRECTION 0x02
-
-enum I8271_STATE_t
-{
- I8271_STATE_EXECUTION_READ = 0,
- I8271_STATE_EXECUTION_WRITE
-};
-
-/* commands accepted */
-#define I8271_COMMAND_SPECIFY 0x035
-#define I8271_COMMAND_SEEK 0x029
-#define I8271_COMMAND_READ_DRIVE_STATUS 0x02c
-#define I8271_COMMAND_READ_SPECIAL_REGISTER 0x03d
-#define I8271_COMMAND_WRITE_SPECIAL_REGISTER 0x03a
-#define I8271_COMMAND_FORMAT 0x023
-#define I8271_COMMAND_READ_ID 0x01b
-#define I8271_COMMAND_READ_DATA_SINGLE_RECORD 0x012
-#define I8271_COMMAND_READ_DATA_AND_DELETED_DATA_SINGLE_RECORD 0x016
-#define I8271_COMMAND_WRITE_DATA_SINGLE_RECORD 0x00a
-#define I8271_COMMAND_WRITE_DELETED_DATA_SINGLE_RECORD 0x00e
-#define I8271_COMMAND_VERIFY_DATA_AND_DELETED_DATA_SINGLE_RECORD 0x01e
-#define I8271_COMMAND_READ_DATA_MULTI_RECORD 0x013
-#define I8271_COMMAND_READ_DATA_AND_DELETED_DATA_MULTI_RECORD 0x017
-#define I8271_COMMAND_WRITE_DATA_MULTI_RECORD 0x00b
-#define I8271_COMMAND_WRITE_DELETED_DATA_MULTI_RECORD 0x00f
-#define I8271_COMMAND_VERIFY_DATA_AND_DELETED_DATA_MULTI_RECORD 0x01f
-#define I8271_COMMAND_SCAN_DATA 0x000
-#define I8271_COMMAND_SCAN_DATA_AND_DELETED_DATA 0x004
-
-/*
-#define I8271_COMMAND_READ_OPERATION (1<<4)
-#define I8271_COMMAND_DELETED_DATA (1<<2)
-#define I8271_COMMAND_MULTI_RECORD (1<<0)
-*/
-
-
-
-/* first parameter for specify command */
-#define I8271_SPECIFY_INITIALIZATION 0x0d
-#define I8271_SPECIFY_LOAD_BAD_TRACKS_SURFACE_0 0x010
-#define I8271_SPECIFY_LOAD_BAD_TRACKS_SURFACE_1 0x018
-
-/* first parameter for read/write special register */
-#define I8271_SPECIAL_REGISTER_SCAN_SECTOR_NUMBER 0x06
-#define I8271_SPECIAL_REGISTER_SCAN_MSB_OF_COUNT 0x014
-#define I8271_SPECIAL_REGISTER_SCAN_LSB_OF_COUNT 0x013
-#define I8271_SPECIAL_REGISTER_SURFACE_0_CURRENT_TRACK 0x012
-#define I8271_SPECIAL_REGISTER_SURFACE_1_CURRENT_TRACK 0x01a
-#define I8271_SPECIAL_REGISTER_MODE_REGISTER 0x017
-#define I8271_SPECIAL_REGISTER_DRIVE_CONTROL_OUTPUT_PORT 0x023
-#define I8271_SPECIAL_REGISTER_DRIVE_CONTROL_INPUT_PORT 0x022
-#define I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_1 0x010
-#define I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_2 0x011
-#define I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_1 0x018
-#define I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_2 0x019
-
-
-/* status register bits */
-#define I8271_STATUS_COMMAND_BUSY 0x080
-#define I8271_STATUS_COMMAND_FULL 0x040
-#define I8271_STATUS_PARAMETER_FULL 0x020
-#define I8271_STATUS_RESULT_FULL 0x010
-#define I8271_STATUS_INT_REQUEST 0x008
-#define I8271_STATUS_NON_DMA_REQUEST 0x004
-
-#define VERBOSE 0
-
-#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
-#define FDC_LOG(x) do { if (VERBOSE) logerror("I8271: %s\n",x); } while (0)
-#define FDC_LOG_COMMAND(x) do { if (VERBOSE) logerror("I8271: COMMAND %s\n",x); } while (0)
-
-
-/* Device Interface */
-
const device_type I8271 = &device_creator<i8271_device>;
i8271_device::i8271_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : device_t(mconfig, I8271, "Intel 8271", tag, owner, clock, "i8271", __FILE__),
- m_write_irq(*this),
- m_write_drq(*this),
- m_floppy_tag1(NULL),
- m_floppy_tag2(NULL),
- m_flags(0),
- m_state(0),
- m_Command(0),
- m_StatusRegister(0),
- m_CommandRegister(0),
- m_ResultRegister(0),
- m_ParameterRegister(0),
- m_ResetRegister(0),
- m_data(0),
- m_ParameterCount(0),
- m_ParameterCountWritten(0),
- m_Mode(0),
- m_drive(0),
- m_side(0),
- m_drive_control_output(0),
- m_drive_control_input(0),
- m_StepRate(0),
- m_HeadSettlingTime(0),
- m_IndexCountBeforeHeadUnload(0),
- m_HeadLoadTime(0),
- //m_ID_C(0),
- //m_ID_H(0),
- m_ID_R(0),
- m_ID_N(0),
- m_data_id(0),
- m_ExecutionPhaseTransferCount(0),
- m_ExecutionPhaseCount(0),
- m_Counter(0)
- //m_data_direction(0)
+ : device_t(mconfig, I8271, "Intel 8271", tag, owner, clock, "i8271n", __FILE__),
+ intrq_cb(*this),
+ drq_cb(*this),
+ hdl_cb(*this),
+ opt_cb(*this)
{
- for (int i = 0; i < 8; i++ )
- {
- m_CommandParameters[i] = 0;
- }
-
- for (int i = 0; i < 2; i++ )
- {
- m_CurrentTrack[i] = 0;
- }
-
- for (int i = 0; i < 4; i++ )
- {
- m_BadTracks[i] = 0;
- }
+ select_connected = true;
+ external_ready = false;
}
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
+DEVICE_ADDRESS_MAP_START(map, 8, i8271_device)
+ AM_RANGE(0x0, 0x0) AM_READWRITE(sr_r, cmd_w)
+ AM_RANGE(0x1, 0x1) AM_READWRITE(rr_r, param_w)
+ AM_RANGE(0x2, 0x2) AM_WRITE(reset_w)
+ADDRESS_MAP_END
-void i8271_device::device_start()
+void i8271_device::set_ready_line_connected(bool _ready)
{
- m_write_irq.resolve_safe();
- m_write_drq.resolve_safe();
-
- m_data_timer = timer_alloc(TIMER_DATA_CALLBACK);
- m_command_complete_timer = timer_alloc(TIMER_TIMED_COMMAND_COMPLETE);
- m_drive = 0;
- m_pExecutionPhaseData = auto_alloc_array(machine(), char, 0x4000);
-
- m_floppy[0] = machine().device<legacy_floppy_image_device>(m_floppy_tag1);
- m_floppy[1] = machine().device<legacy_floppy_image_device>(m_floppy_tag2);
-
- // register for state saving
- /*save_item(NAME(m_flags));
- save_item(NAME(m_state));
- save_item(NAME(m_Command));
- save_item(NAME(m_StatusRegister));
- save_item(NAME(m_CommandRegister));
- save_item(NAME(m_ResultRegister));
- save_item(NAME(m_ParameterRegister));
- save_item(NAME(m_ResetRegister));
- save_item(NAME(m_data));
- //save_item(NAME(m_ParameterCount));
- //save_item(NAME(m_ParameterCountWritten));
- save_item(NAME(m_CommandParameters));
- //save_item(NAME(m_CurrentTrack));
- //save_item(NAME(m_BadTracks));
- //save_item(NAME(m_Mode));
- save_item(NAME(m_drive));
- save_item(NAME(m_side));
- save_item(NAME(m_drive_control_output));
- save_item(NAME(m_drive_control_input));
- //save_item(NAME(m_StepRate));
- //save_item(NAME(m_HeadSettlingTime));
- //save_item(NAME(m_IndexCountBeforeHeadUnload));
- //save_item(NAME(m_HeadLoadTime));
- save_item(NAME(m_ID_C));
- save_item(NAME(m_ID_H));
- save_item(NAME(m_ID_R));
- save_item(NAME(m_ID_N));
- save_item(NAME(m_data_id));
- save_item(NAME(m_ExecutionPhaseTransferCount));
- save_item(NAME(m_ExecutionPhaseCount));
- save_item(NAME(m_Counter));
- save_item(NAME(m_data_direction));
- save_pointer(NAME(m_pExecutionPhaseData), 0x4000);*/
+ ready_connected = _ready;
}
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void i8271_device::device_reset()
+void i8271_device::set_select_lines_connected(bool _select)
{
- m_StatusRegister = 0; //I8271_STATUS_INT_REQUEST | I8271_STATUS_NON_DMA_REQUEST;
- m_Mode = 0x0c0; /* bits 0, 1 are initialized to zero */
- m_ParameterCountWritten = 0;
- m_ParameterCount = 0;
-
- /* if timer is active remove */
- m_command_complete_timer->reset();
- m_data_timer->reset();
-
- /* clear irq */
- set_irq_state(0);
- /* clear dma */
- set_dma_drq();
+ select_connected = _select;
}
-void i8271_device::seek_to_track(int track)
+void i8271_device::device_start()
{
- if (track==0)
- {
- /* seek to track 0 */
- unsigned char StepCount = 0x0ff;
-
- /*logerror("step\n"); */
-
- /* track 0 not set, not seeked more than 255 tracks */
- while (m_floppy[m_drive]->floppy_tk00_r() && (StepCount != 0))
- {
-/* logerror("step\n"); */
- StepCount--;
- m_floppy[m_drive]->floppy_drive_seek(-1);
- }
-
- m_CurrentTrack[m_drive] = 0;
-
- /* failed to find track 0? */
- if (StepCount==0)
- {
- /* Completion Type: operator intervation probably required for recovery */
- /* Completion code: track 0 not found */
- m_ResultRegister |= (2<<3) | 2<<1;
- }
-
- /* step out - towards track 0 */
- m_drive_control_output &=~(1<<2);
+ intrq_cb.resolve_safe();
+ drq_cb.resolve_safe();
+ hdl_cb.resolve_safe();
+ opt_cb.resolve_safe();
+
+ for(int i=0; i != 2; i++) {
+ char name[2];
+ flopi[i].tm = timer_alloc(i);
+ flopi[i].id = i;
+ if(select_connected) {
+ name[0] = '0'+i;
+ name[1] = 0;
+ floppy_connector *con = subdevice<floppy_connector>(name);
+ if(con) {
+ flopi[i].dev = con->get_device();
+ if (flopi[i].dev != NULL)
+ flopi[i].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(i8271_device::index_callback), this));
+ } else
+ flopi[i].dev = NULL;
+ } else
+ flopi[i].dev = NULL;
+
+ flopi[i].main_state = IDLE;
+ flopi[i].sub_state = IDLE;
+ flopi[i].dir = 0;
+ flopi[i].counter = 0;
+ flopi[i].pcn = 0;
+ flopi[i].live = false;
+ flopi[i].index = false;
+ flopi[i].ready = true;
}
- else
- {
- signed int SignedTracks;
-
- /* calculate number of tracks to seek */
- SignedTracks = track - m_CurrentTrack[m_drive];
-
- /* step towards 0 */
- m_drive_control_output &= ~(1<<2);
+ cur_rate = 250000;
- if (SignedTracks>0)
- {
- /* step away from 0 */
- m_drive_control_output |= (1<<2);
- }
-
-
- /* seek to track 0 */
- m_floppy[m_drive]->floppy_drive_seek(SignedTracks);
-
- m_CurrentTrack[m_drive] = track;
- }
+ cur_live.tm = attotime::never;
+ cur_live.state = IDLE;
+ cur_live.next_state = -1;
+ cur_live.fi = NULL;
}
-void i8271_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+void i8271_device::device_reset()
{
- switch (id)
- {
- case TIMER_DATA_CALLBACK:
- /* ok, trigger data request now */
- data_request();
-
- /* stop it */
- m_data_timer->reset();
- break;
-
- case TIMER_TIMED_COMMAND_COMPLETE:
- command_complete(1,1);
-
- /* stop it, but don't allow it to be free'd */
- m_command_complete_timer->reset();
- break;
+ soft_reset();
+}
- default:
- break;
+void i8271_device::soft_reset()
+{
+ main_phase = PHASE_IDLE;
+ for(int i=0; i<2; i++) {
+ flopi[i].main_state = IDLE;
+ flopi[i].sub_state = IDLE;
+ flopi[i].live = false;
+ flopi[i].ready = get_ready(i);
}
+ set_irq(false);
+ set_drq(false);
+ command_pos = 0;
+ cur_live.fi = 0;
+ cur_live.tm = attotime::never;
+ cur_live.state = IDLE;
+ cur_live.next_state = -1;
+ cur_live.fi = NULL;
+ rr = 0;
+ scan_sec = 0;
+ moder = 0xc0;
+ scan_cnt[0] = scan_cnt[1] = 0;
}
-/* setup a timed data request - data request will be triggered in a few usecs time */
-void i8271_device::timed_data_request()
+void i8271_device::ready_w(bool _ready)
{
- int usecs;
- /* 64 for single density */
- usecs = 64;
-
- /* set timers */
- m_command_complete_timer->reset();
- m_data_timer->adjust(attotime::from_usec(usecs));
+ external_ready = _ready;
}
-
-/* setup a irq to occur 128us later - in reality this would be much later, because the int would
-come after reading the two CRC bytes at least! This function is used when a irq is required at
-command completion. Required for read data and write data, where last byte could be missed! */
-void i8271_device::timed_command_complete()
+bool i8271_device::get_ready(int fid)
{
- int usecs;
-
- /* 64 for single density - 2 crc bytes later*/
- usecs = 64*2;
-
- /* set timers */
- m_data_timer->reset();
- m_command_complete_timer->adjust(attotime::from_usec(usecs));
+ if(!flopi[fid].ready)
+ return false;
+ if(ready_connected)
+ return flopi[fid].dev ? !flopi[fid].dev->ready_r() : false;
+ return !external_ready;
}
-void i8271_device::set_irq_state(int state)
+void i8271_device::set_floppy(floppy_image_device *flop)
{
- m_StatusRegister &= ~I8271_STATUS_INT_REQUEST;
- if (state)
- {
- m_StatusRegister |= I8271_STATUS_INT_REQUEST;
+ for(int fid=0; fid<2; fid++) {
+ if(flopi[fid].dev)
+ flopi[fid].dev->setup_index_pulse_cb(floppy_image_device::index_pulse_cb());
+ flopi[fid].dev = flop;
}
-
- m_write_irq((m_StatusRegister & I8271_STATUS_INT_REQUEST) ? ASSERT_LINE : CLEAR_LINE);
+ if(flop)
+ flop->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(FUNC(i8271_device::index_callback), this));
}
-void i8271_device::set_dma_drq()
+READ8_MEMBER(i8271_device::sr_r)
{
- m_write_drq((m_flags & I8271_FLAGS_DATA_REQUEST) ? 1 : 0);
+ UINT32 ret = (irq ? SR_IRQ : 0);
+ switch(main_phase) {
+ case PHASE_CMD:
+ ret |= SR_CF;
+ break;
+ case PHASE_EXEC:
+ ret |= SR_BSY;
+ if((moder & 1) && drq)
+ ret |= SR_DRQ;
+ break;
+ case PHASE_RESULT:
+ ret |= SR_RF;
+ break;
+ }
+ return ret;
}
-void i8271_device::load_bad_tracks(int surface)
+READ8_MEMBER(i8271_device::rr_r)
{
- m_BadTracks[(surface<<1) + 0] = m_CommandParameters[1];
- m_BadTracks[(surface<<1) + 1] = m_CommandParameters[2];
- m_CurrentTrack[surface] = m_CommandParameters[3];
+ if(main_phase == PHASE_RESULT)
+ main_phase = PHASE_IDLE;
+ set_irq(false);
+ return rr;
}
-void i8271_device::write_bad_track(int surface, int track, int data)
+void i8271_device::set_rate(int rate)
{
- m_BadTracks[(surface<<1) + (track-1)] = data;
+ cur_rate = rate;
}
-void i8271_device::write_current_track(int surface, int track)
+READ8_MEMBER(i8271_device::data_r)
{
- m_CurrentTrack[surface] = track;
+ set_drq(false);
+ return dma_data;
}
-int i8271_device::read_current_track(int surface)
+WRITE8_MEMBER(i8271_device::data_w)
{
- return m_CurrentTrack[surface];
+ if(drq) {
+ set_drq(false);
+ dma_data = data;
+ }
}
-int i8271_device::read_bad_track(int surface, int track)
+WRITE8_MEMBER(i8271_device::cmd_w)
{
- return m_BadTracks[(surface<<1) + (track-1)];
+ if(main_phase == PHASE_IDLE) {
+ command[0] = data;
+ command_pos = 1;
+
+ int cmd = check_command();
+ if(cmd != C_INVALID) {
+ main_phase = PHASE_CMD;
+ if(cmd != C_INCOMPLETE)
+ start_command(cmd);
+ }
+ }
}
-void i8271_device::get_drive()
+WRITE8_MEMBER(i8271_device::param_w)
{
- /* &40 = drive 0 side 0 */
- /* &80 = drive 1 side 0 */
-
-
-
- if (m_CommandRegister & (1<<6))
- {
- m_drive = 0;
+ if(main_phase == PHASE_CMD) {
+ command[command_pos++] = data;
+ int cmd = check_command();
+ if(cmd != C_INCOMPLETE)
+ start_command(cmd);
}
-
- if (m_CommandRegister & (1<<7))
- {
- m_drive = 1;
- }
-
}
-void i8271_device::check_all_parameters_written()
+bool i8271_device::set_output(UINT8 data)
{
- if (m_ParameterCount == m_ParameterCountWritten)
- {
- m_StatusRegister &= ~I8271_STATUS_COMMAND_FULL;
-
- command_execute();
+ if(main_phase == PHASE_EXEC) {
+ if(drq) {
+ rr = ERR_DMA;
+ return false;
+ }
+ dma_data = data;
+ set_drq(true);
}
+ return true;
}
-
-void i8271_device::update_state()
+bool i8271_device::get_input(UINT8 *data)
{
- switch (m_state)
- {
- /* fdc reading data and passing it to cpu which must read it */
- case I8271_STATE_EXECUTION_READ:
- {
- // /* if data request has been cleared, i.e. caused by a read of the register */
- // if ((m_flags & I8271_FLAGS_DATA_REQUEST)==0)
- {
- /* setup data with byte */
- m_data = m_pExecutionPhaseData[m_ExecutionPhaseCount];
-
-/* logerror("read data %02x\n", m_data); */
-
- /* update counters */
- m_ExecutionPhaseCount++;
- m_ExecutionPhaseTransferCount--;
-
- // logerror("Count: %04x\n", m_ExecutionPhaseCount);
- // logerror("Remaining: %04x\n", m_ExecutionPhaseTransferCount);
-
- /* completed? */
- if (m_ExecutionPhaseTransferCount==0)
- {
- /* yes */
-
- // logerror("sector read complete!\n");
- /* continue command */
- command_continue();
- }
- else
- {
- /* no */
-
- /* issue data request */
- timed_data_request();
- }
- }
+ if(main_phase == PHASE_EXEC) {
+ if(drq) {
+ rr = ERR_DMA;
+ return false;
}
- break;
-
- /* fdc reading data and passing it to cpu which must read it */
- case I8271_STATE_EXECUTION_WRITE:
- {
- /* setup data with byte */
- m_pExecutionPhaseData[m_ExecutionPhaseCount] = m_data;
- /* update counters */
- m_ExecutionPhaseCount++;
- m_ExecutionPhaseTransferCount--;
-
- /* completed? */
- if (m_ExecutionPhaseTransferCount==0)
- {
- /* yes */
-
- /* continue command */
- command_continue();
- }
- else
- {
- /* no */
-
- /* issue data request */
- timed_data_request();
- }
- }
- break;
-
- default:
- break;
+ *data = dma_data;
+ set_drq(true);
}
+ return true;
}
-void i8271_device::initialise_execution_phase_read(int transfer_size)
+void i8271_device::set_drq(bool state)
{
- /* read */
- m_flags |= I8271_FLAGS_DATA_DIRECTION;
- m_ExecutionPhaseCount = 0;
- m_ExecutionPhaseTransferCount = transfer_size;
- m_state = I8271_STATE_EXECUTION_READ;
+ if(state != drq) {
+ drq = state;
+ drq_cb(drq);
+ if(moder & 1)
+ intrq_cb(drq);
+ }
}
-
-void i8271_device::initialise_execution_phase_write(int transfer_size)
+void i8271_device::set_irq(bool state)
{
- /* write */
- m_flags &= ~I8271_FLAGS_DATA_DIRECTION;
- m_ExecutionPhaseCount = 0;
- m_ExecutionPhaseTransferCount = transfer_size;
- m_state = I8271_STATE_EXECUTION_WRITE;
+ if(state != irq) {
+ irq = state;
+ intrq_cb(irq);
+ }
}
-/* for data transfers */
-void i8271_device::data_request()
+void i8271_device::live_start(floppy_info &fi, int state)
{
- m_flags |= I8271_FLAGS_DATA_REQUEST;
-
- if ((m_Mode & 0x01)!=0)
- {
- /* non-dma */
- m_StatusRegister |= I8271_STATUS_NON_DMA_REQUEST;
- /* set int */
- set_irq_state(1);
- }
- else
- {
- /* dma */
- m_StatusRegister &= ~I8271_STATUS_NON_DMA_REQUEST;
-
- set_dma_drq();
- }
+ cur_live.tm = machine().time();
+ cur_live.state = state;
+ cur_live.next_state = -1;
+ cur_live.fi = &fi;
+ cur_live.shift_reg = 0;
+ cur_live.crc = 0xffff;
+ cur_live.bit_counter = 0;
+ cur_live.data_separator_phase = false;
+ cur_live.data_reg = 0;
+ cur_live.previous_type = live_info::PT_NONE;
+ cur_live.data_bit_context = false;
+ cur_live.byte_counter = 0;
+ cur_live.pll.reset(cur_live.tm);
+ cur_live.pll.set_clock(attotime::from_hz(cur_rate));
+ checkpoint_live = cur_live;
+ fi.live = true;
+
+ live_run();
}
-void i8271_device::command_complete(int result, int int_rq)
+void i8271_device::checkpoint()
{
- /* not busy, and not a execution phase data request in non-dma mode */
- m_StatusRegister &= ~(I8271_STATUS_COMMAND_BUSY | I8271_STATUS_NON_DMA_REQUEST);
-
- if (result)
- {
- m_StatusRegister |= I8271_STATUS_RESULT_FULL;
- }
-
- if (int_rq)
- {
- /* trigger an int */
- set_irq_state(1);
- }
-
- /* correct?? */
- m_drive_control_output &=~1;
+ if(cur_live.fi)
+ cur_live.pll.commit(cur_live.fi->dev, cur_live.tm);
+ checkpoint_live = cur_live;
}
-
-/* for data transfers */
-void i8271_device::clear_data_request()
+void i8271_device::rollback()
{
- m_flags &= ~I8271_FLAGS_DATA_REQUEST;
+ cur_live = checkpoint_live;
+}
- if ((m_Mode & 0x01)!=0)
- {
- /* non-dma */
- m_StatusRegister &= ~I8271_STATUS_NON_DMA_REQUEST;
- /* set int */
- set_irq_state(0);
- }
+void i8271_device::live_delay(int state)
+{
+ cur_live.next_state = state;
+ if(cur_live.tm != machine().time())
+ cur_live.fi->tm->adjust(cur_live.tm - machine().time());
else
- {
- /* dma */
- set_dma_drq();
- }
+ live_sync();
}
-
-void i8271_device::command_continue()
+void i8271_device::live_sync()
{
- switch (m_Command)
- {
- case I8271_COMMAND_READ_DATA_MULTI_RECORD:
- case I8271_COMMAND_READ_DATA_SINGLE_RECORD:
- {
- /* completed all sectors? */
- m_Counter--;
- /* increment sector id */
- m_ID_R++;
-
- /* end command? */
- if (m_Counter==0)
- {
- timed_command_complete();
- return;
+ if(!cur_live.tm.is_never()) {
+ if(cur_live.tm > machine().time()) {
+ rollback();
+ live_run(machine().time());
+ cur_live.pll.commit(cur_live.fi->dev, cur_live.tm);
+ } else {
+ cur_live.pll.commit(cur_live.fi->dev, cur_live.tm);
+ if(cur_live.next_state != -1) {
+ cur_live.state = cur_live.next_state;
+ cur_live.next_state = -1;
}
-
- do_read();
- }
- break;
-
- case I8271_COMMAND_WRITE_DATA_MULTI_RECORD:
- case I8271_COMMAND_WRITE_DATA_SINGLE_RECORD:
- {
- /* put the buffer to the sector */
- m_floppy[m_drive]->floppy_drive_write_sector_data(m_side, m_data_id, m_pExecutionPhaseData, 1<<(m_ID_N+7),0);
-
- /* completed all sectors? */
- m_Counter--;
- /* increment sector id */
- m_ID_R++;
-
- /* end command? */
- if (m_Counter==0)
- {
- timed_command_complete();
- return;
+ if(cur_live.state == IDLE) {
+ cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm);
+ cur_live.tm = attotime::never;
+ cur_live.fi->live = false;
+ cur_live.fi = 0;
}
-
- do_write();
}
- break;
-
- case I8271_COMMAND_READ_ID:
- {
- m_Counter--;
-
- if (m_Counter==0)
- {
- timed_command_complete();
- return;
- }
-
- do_read_id();
- }
- break;
-
- default:
- break;
+ cur_live.next_state = -1;
+ checkpoint();
}
}
-void i8271_device::do_read()
+void i8271_device::live_abort()
{
- /* find the sector */
- if (find_sector())
- {
- /* get the sector into the buffer */
- m_floppy[m_drive]->floppy_drive_read_sector_data(m_side, m_data_id, m_pExecutionPhaseData, 1<<(m_ID_N+7));
-
- /* initialise for reading */
- initialise_execution_phase_read(1<<(m_ID_N+7));
-
- /* update state - gets first byte and triggers a data request */
- timed_data_request();
- return;
+ if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) {
+ rollback();
+ live_run(machine().time());
}
- LOG(("error getting sector data\n"));
- timed_command_complete();
-}
-
-void i8271_device::do_read_id()
-{
- chrn_id id;
-
- /* get next id from disc */
- m_floppy[m_drive]->floppy_drive_get_next_id(m_side,&id);
-
- m_pExecutionPhaseData[0] = id.C;
- m_pExecutionPhaseData[1] = id.H;
- m_pExecutionPhaseData[2] = id.R;
- m_pExecutionPhaseData[3] = id.N;
-
- initialise_execution_phase_read(4);
-}
-
-
-void i8271_device::do_write()
-{
- /* find the sector */
- if (find_sector())
- {
- /* initialise for reading */
- initialise_execution_phase_write(1<<(m_ID_N+7));
-
- /* update state - gets first byte and triggers a data request */
- timed_data_request();
- return;
+ if(cur_live.fi) {
+ cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm);
+ cur_live.fi->live = false;
+ cur_live.fi = 0;
}
- LOG(("error getting sector data\n"));
- timed_command_complete();
+ cur_live.tm = attotime::never;
+ cur_live.state = IDLE;
+ cur_live.next_state = -1;
}
-
-
-int i8271_device::find_sector()
+void i8271_device::live_run(attotime limit)
{
-// int track_count_attempt;
-
-// track_count_attempt
- /* find sector within one revolution of the disc - 2 index pulses */
-
- /* number of times we have seen index hole */
- int index_count = 0;
-
- /* get sector id's */
- do
- {
- chrn_id id;
+ if(cur_live.state == IDLE || cur_live.next_state != -1)
+ return;
- /* get next id from disc */
- if (m_floppy[m_drive]->floppy_drive_get_next_id(m_side,&id))
- {
- /* tested on Amstrad CPC - All bytes must match, otherwise
- a NO DATA error is reported */
- if (id.R == m_ID_R)
- {
- /* TODO: Is this correct? What about bad tracks? */
- if (id.C == m_CurrentTrack[m_drive])
- {
- m_data_id = id.data_id;
- return 1;
- }
- else
- {
- /* TODO: if track doesn't match, the real 8271 does a step */
+ if(limit == attotime::never) {
+ if(cur_live.fi->dev)
+ limit = cur_live.fi->dev->time_next_index();
+ if(limit == attotime::never) {
+ // Happens when there's no disk or if the fdc is not
+ // connected to a drive, hence no index pulse. Force a
+ // sync from time to time in that case, so that the main
+ // cpu timeout isn't too painful. Avoids looping into
+ // infinity looking for data too.
+
+ limit = machine().time() + attotime::from_msec(1);
+ cur_live.fi->tm->adjust(attotime::from_msec(1));
+ }
+ }
+ for(;;) {
+ switch(cur_live.state) {
+ case SEARCH_ADDRESS_MARK_HEADER:
+ if(read_one_bit(limit))
+ return;
+#if 0
+ fprintf(stderr, "%s: shift = %04x data=%02x c=%d\n", tts(cur_live.tm).c_str(), cur_live.shift_reg,
+ (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
+ (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
+ (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
+ (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) |
+ (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) |
+ (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) |
+ (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) |
+ (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00),
+ cur_live.bit_counter);
+#endif
+
+ if(cur_live.shift_reg == 0xf57e) {
+ cur_live.crc = 0xef21;
+ cur_live.data_separator_phase = false;
+ cur_live.bit_counter = 0;
+ cur_live.state = READ_ID_BLOCK;
+ }
+ break;
- return 0;
+ case READ_ID_BLOCK: {
+ if(read_one_bit(limit))
+ return;
+ if(cur_live.bit_counter & 15)
+ break;
+ int slot = (cur_live.bit_counter >> 4)-1;
+
+ if(0)
+ fprintf(stderr, "%s: slot=%d data=%02x crc=%04x\n", tts(cur_live.tm).c_str(), slot, cur_live.data_reg, cur_live.crc);
+ cur_live.idbuf[slot] = cur_live.data_reg;
+ if(cur_live.fi->main_state == READ_ID) {
+ if(!set_output(cur_live.data_reg)) {
+ live_delay(IDLE);
+ return;
}
}
+ if(slot == 5) {
+ live_delay(IDLE);
+ return;
+ }
+ break;
}
- /* index set? */
- if (m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_INDEX))
- {
- index_count++;
- }
-
- }
- while (index_count!=2);
-
- /* completion type: command/drive error */
- /* completion code: sector not found */
- m_ResultRegister |= (3<<3);
-
- return 0;
-}
+ case SEARCH_ADDRESS_MARK_DATA:
+ if(read_one_bit(limit))
+ return;
+#if 0
+ fprintf(stderr, "%s: shift = %04x data=%02x c=%d.%x\n", tts(cur_live.tm).c_str(), cur_live.shift_reg,
+ (cur_live.shift_reg & 0x4000 ? 0x80 : 0x00) |
+ (cur_live.shift_reg & 0x1000 ? 0x40 : 0x00) |
+ (cur_live.shift_reg & 0x0400 ? 0x20 : 0x00) |
+ (cur_live.shift_reg & 0x0100 ? 0x10 : 0x00) |
+ (cur_live.shift_reg & 0x0040 ? 0x08 : 0x00) |
+ (cur_live.shift_reg & 0x0010 ? 0x04 : 0x00) |
+ (cur_live.shift_reg & 0x0004 ? 0x02 : 0x00) |
+ (cur_live.shift_reg & 0x0001 ? 0x01 : 0x00),
+ cur_live.bit_counter >> 4, cur_live.bit_counter & 15);
+#endif
+
+ if(cur_live.bit_counter > 23*16) {
+ live_delay(SEARCH_ADDRESS_MARK_DATA_FAILED);
+ return;
+ }
-void i8271_device::command_execute()
-{
- /* clear it = good completion status */
- /* this will be changed if anything bad happens! */
- m_ResultRegister = 0;
+ if(cur_live.bit_counter >= 11*16 && (cur_live.shift_reg == 0xf56a || cur_live.shift_reg == 0xf56f)) {
+ cur_live.crc = cur_live.shift_reg == 0xf56a ? 0x8fe7 : 0xbf84;
+ cur_live.data_separator_phase = false;
+ cur_live.bit_counter = 0;
+ cur_live.state = READ_SECTOR_DATA;
+ }
- switch (m_Command)
- {
- case I8271_COMMAND_SPECIFY:
- {
- switch (m_CommandParameters[0])
- {
- case 0x0d:
- {
- LOG(("Initialization\n"));
- m_StepRate = m_CommandParameters[1];
- m_HeadSettlingTime = m_CommandParameters[2];
- m_IndexCountBeforeHeadUnload = (m_CommandParameters[3]>>4) & 0x0f;
- m_HeadLoadTime = (m_CommandParameters[3] & 0x0f);
- }
- break;
+ break;
- case 0x010:
- {
- LOG(("Load bad Tracks Surface 0\n"));
- load_bad_tracks(0);
+ case SEARCH_ADDRESS_MARK_DATA_FAILED:
+ cur_live.state = IDLE;
+ return;
- }
+ case READ_SECTOR_DATA: {
+ if(read_one_bit(limit))
+ return;
+ if(cur_live.bit_counter & 15)
break;
-
- case 0x018:
- {
- LOG(("Load bad Tracks Surface 1\n"));
- load_bad_tracks(1);
-
+ int slot = (cur_live.bit_counter >> 4)-1;
+ if(slot < sector_size) {
+ // Sector data
+ if(cur_live.fi->main_state == SCAN_DATA)
+ live_delay(SCAN_SECTOR_DATA_BYTE);
+ else if(cur_live.fi->main_state == VERIFY_DATA)
+ live_delay(VERIFY_SECTOR_DATA_BYTE);
+ else
+ live_delay(READ_SECTOR_DATA_BYTE);
+ return;
+ } else if(slot < sector_size+2) {
+ // CRC
+ if(slot == sector_size+1) {
+ live_delay(IDLE);
+ return;
}
- break;
}
-
- /* no result */
- command_complete(0,0);
+ break;
}
- break;
- case I8271_COMMAND_READ_SPECIAL_REGISTER:
- {
- /* unknown - what is read when a special register that isn't allowed is specified? */
- int data = 0x0ff;
+ case READ_SECTOR_DATA_BYTE:
+ if(!set_output(cur_live.data_reg)) {
+ live_delay(IDLE);
+ return;
+ }
+ cur_live.state = READ_SECTOR_DATA;
+ checkpoint();
+ break;
- switch (m_CommandParameters[0])
+ case SCAN_SECTOR_DATA_BYTE:
+ if(!scan_done)
{
- case I8271_SPECIAL_REGISTER_MODE_REGISTER:
+ UINT8 data;
+ if(!get_input(&data)) {
+ live_delay(IDLE);
+ return;
+ }
+ if(cur_live.data_reg != 0xff)
{
- data = m_Mode;
+ switch(command[4] & 0xc0) {
+ case 0:
+ if(cur_live.data_reg != data)
+ scan_match = false;
+ break;
+ case 1:
+ if(cur_live.data_reg < data)
+ scan_match = false;
+ break;
+ case 2:
+ if(cur_live.data_reg > data)
+ scan_match = false;
+ break;
+ default:
+ scan_match = false;
+ break;
+ }
}
- break;
+ scan_len++;
+ if(scan_len == command[5]) {
+ if(scan_match) {
+ int slot = calc_sector_size(command[3] >> 5) - ((cur_live.bit_counter >> 4)-1);
+ scan_sec = cur_live.idbuf[2];
+ scan_cnt[0] = slot & 0x7f;
+ scan_cnt[1] = slot >> 9;
+ scan_done = true;
+ rr = command[4] & 0xc0 ? ERR_SMNE : ERR_SMEQ;
+ }
+ else
+ {
+ scan_match = true;
+ scan_len = 0;
+ }
+ }
+ }
+ cur_live.state = READ_SECTOR_DATA;
+ checkpoint();
+ break;
- case I8271_SPECIAL_REGISTER_SURFACE_0_CURRENT_TRACK:
- {
- data = read_current_track(0);
+ case VERIFY_SECTOR_DATA_BYTE:
+ cur_live.state = READ_SECTOR_DATA;
+ checkpoint();
+ break;
- }
- break;
+ case WRITE_SECTOR_SKIP_GAP2:
+ cur_live.bit_counter = 0;
+ cur_live.byte_counter = 0;
+ cur_live.state = WRITE_SECTOR_SKIP_GAP2_BYTE;
+ checkpoint();
+ break;
- case I8271_SPECIAL_REGISTER_SURFACE_1_CURRENT_TRACK:
- {
- data = read_current_track(1);
- }
+ case WRITE_SECTOR_SKIP_GAP2_BYTE:
+ if(read_one_bit(limit))
+ return;
+ if(cur_live.bit_counter != 11*16)
break;
-
- case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_1:
- {
- data = read_bad_track(0,1);
+ cur_live.bit_counter = 0;
+ cur_live.byte_counter = 0;
+ live_delay(WRITE_SECTOR_DATA);
+ return;
+
+ case WRITE_SECTOR_DATA:
+ if(cur_live.byte_counter < 6)
+ live_write_fm(0x00);
+ else if(cur_live.byte_counter < 7) {
+ cur_live.crc = 0xffff;
+ live_write_raw(BIT(command[0], 2) ? 0xf56a : 0xf56f);
+ } else if(cur_live.byte_counter < 7+sector_size) {
+ UINT8 data;
+ if(!get_input(&data)) {
+ live_delay(IDLE);
+ return;
}
- break;
+ live_write_fm(data);
+ }
+ else if(cur_live.byte_counter < 7+sector_size+2)
+ live_write_fm(cur_live.crc >> 8);
+ else if(cur_live.byte_counter < 7+sector_size+2+1)
+ live_write_fm(0xff);
+ else {
+ cur_live.pll.stop_writing(cur_live.fi->dev, cur_live.tm);
+ cur_live.state = IDLE;
+ return;
+ }
+ cur_live.state = WRITE_SECTOR_DATA_BYTE;
+ cur_live.bit_counter = 16;
+ checkpoint();
+ break;
- case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_2:
- {
- data = read_bad_track(0,2);
+ case WRITE_TRACK_PRE_SECTORS:
+ if(command[4]) {
+ if(cur_live.byte_counter < command[4])
+ live_write_fm(0xff);
+ else if(cur_live.byte_counter < (command[4] + 6))
+ live_write_fm(0x00);
+ else if(cur_live.byte_counter < (command[4] + 7))
+ live_write_raw(0xf77a);
+ else if(cur_live.byte_counter < (command[4] + command[5] + 7))
+ live_write_fm(0xff);
+ else {
+ cur_live.state = WRITE_TRACK_SECTOR;
+ cur_live.byte_counter = 0;
+ break;
}
- break;
-
- case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_1:
- {
- data = read_bad_track(1,1);
+ } else {
+ if(cur_live.byte_counter < command[5])
+ live_write_fm(0xff);
+ else {
+ cur_live.state = WRITE_TRACK_SECTOR;
+ cur_live.byte_counter = 0;
+ break;
}
- break;
+ }
+ cur_live.state = WRITE_TRACK_PRE_SECTORS_BYTE;
+ cur_live.bit_counter = 16;
+ checkpoint();
+ break;
- case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_2:
- {
- data = read_bad_track(1,2);
+ case WRITE_TRACK_SECTOR:
+ if(cur_live.byte_counter < 6)
+ live_write_fm(0x00);
+ else if(cur_live.byte_counter < 7) {
+ cur_live.crc = 0xffff;
+ live_write_raw(0xf57e);
+ } else if(cur_live.byte_counter < 11) {
+ UINT8 data;
+ if(!get_input(&data)) {
+ live_delay(IDLE);
+ return;
}
+ live_write_fm(data);
+ } else if(cur_live.byte_counter < 13)
+ live_write_fm(cur_live.crc >> 8);
+ else if(cur_live.byte_counter < 24)
+ live_write_fm(0xff);
+ else if(cur_live.byte_counter < 30)
+ live_write_fm(0x00);
+ else if(cur_live.byte_counter < 31) {
+ cur_live.crc = 0xffff;
+ live_write_raw(0xf56f);
+ } else if(cur_live.byte_counter < 31+sector_size)
+ live_write_fm(0xe5);
+ else if(cur_live.byte_counter < 33+sector_size)
+ live_write_fm(cur_live.crc >> 8);
+ else if(cur_live.byte_counter < 33+sector_size+command[2])
+ live_write_fm(0xff);
+ else {
+ cur_live.byte_counter = 0;
+ command[3] = (command[3] & 0xe0) | ((command[3] & 0x1f) - 1);
+ cur_live.state = command[3] & 0x1f ? WRITE_TRACK_SECTOR : WRITE_TRACK_POST_SECTORS;
break;
+ }
+ cur_live.state = WRITE_TRACK_SECTOR_BYTE;
+ cur_live.bit_counter = 16;
+ checkpoint();
+ break;
- case I8271_SPECIAL_REGISTER_DRIVE_CONTROL_OUTPUT_PORT:
- {
- FDC_LOG_COMMAND("Read Drive Control Output port\n");
+ case WRITE_TRACK_POST_SECTORS:
+ live_write_fm(0xff);
+ cur_live.state = WRITE_TRACK_POST_SECTORS_BYTE;
+ cur_live.bit_counter = 16;
+ checkpoint();
+ break;
- get_drive();
+ case WRITE_TRACK_PRE_SECTORS_BYTE:
+ case WRITE_TRACK_SECTOR_BYTE:
+ case WRITE_TRACK_POST_SECTORS_BYTE:
+ case WRITE_SECTOR_DATA_BYTE:
+ if(write_one_bit(limit))
+ return;
+ if(cur_live.bit_counter == 0) {
+ cur_live.byte_counter++;
+ live_delay(cur_live.state-1);
+ return;
+ }
+ break;
- /* assumption: select bits reflect the select bits from the previous
- command. i.e. read drive status */
- data = (m_drive_control_output & ~0x0c0) | (m_CommandRegister & 0x0c0);
- }
- break;
+ default:
+ logerror("%s: Unknown live state %d\n", tts(cur_live.tm).c_str(), cur_live.state);
+ return;
+ }
+ }
+}
- case I8271_SPECIAL_REGISTER_DRIVE_CONTROL_INPUT_PORT:
- {
- /* bit 7: not used */
- /* bit 6: ready 1 */
- /* bit 5: write fault */
- /* bit 4: index */
- /* bit 3: wr prot */
- /* bit 2: rdy 0 */
- /* bit 1: track 0 */
- /* bit 0: cnt/opi */
+int i8271_device::check_command()
+{
+ switch(command[0] & 0x3f) {
+ case 0x00:
+ case 0x04:
+ return command_pos == 6 ? C_SCAN : C_INCOMPLETE;
- FDC_LOG_COMMAND("Read Drive Control Input port\n");
+ case 0x0a:
+ case 0x0e:
+ return command_pos == 3 ? C_WRITE_DATA_SINGLE : C_INCOMPLETE;
+ case 0x0b:
+ case 0x0f:
+ return command_pos == 4 ? C_WRITE_DATA_MULTI : C_INCOMPLETE;
- m_drive_control_input = (1<<6) | (1<<2);
+ case 0x12:
+ case 0x16:
+ return command_pos == 3 ? C_READ_DATA_SINGLE : C_INCOMPLETE;
- /* bit 3 = 0 if write protected */
- m_drive_control_input |= m_floppy[m_drive]->floppy_wpt_r() << 3;
+ case 0x13:
+ case 0x17:
+ return command_pos == 4 ? C_READ_DATA_MULTI : C_INCOMPLETE;
- /* bit 1 = 0 if head at track 0 */
- m_drive_control_input |= m_floppy[m_drive]->floppy_tk00_r() << 1;
+ case 0x1e:
+ return command_pos == 3 ? C_VERIFY_DATA_SINGLE : C_INCOMPLETE;
- /* need to setup this register based on drive selected */
- data = m_drive_control_input;
- }
- break;
+ case 0x1f:
+ return command_pos == 4 ? C_VERIFY_DATA_MULTI : C_INCOMPLETE;
- }
+ case 0x1b:
+ return command_pos == 4 ? C_READ_ID : C_INCOMPLETE;
- m_ResultRegister = data;
+ case 0x23:
+ return command_pos == 6 ? C_FORMAT_TRACK : C_INCOMPLETE;
- command_complete(1,0);
- }
- break;
+ case 0x29:
+ return command_pos == 2 ? C_SEEK : C_INCOMPLETE;
+ case 0x2c:
+ return C_READ_DRIVE_STATUS;
- case I8271_COMMAND_WRITE_SPECIAL_REGISTER:
- {
- switch (m_CommandParameters[0])
- {
- case I8271_SPECIAL_REGISTER_MODE_REGISTER:
- {
- /* TODO: Check bits 6-7 and 5-2 are valid */
- m_Mode = m_CommandParameters[1];
+ case 0x35:
+ return command_pos == 5 ? C_SPECIFY : C_INCOMPLETE;
- if (m_Mode & 0x01)
- {
- LOG(("Mode: Non-DMA\n"));
- }
- else
- {
- LOG(("Mode: DMA\n"));
- }
+ case 0x3a:
+ return command_pos == 3 ? C_WRITE_SPECIAL_REGISTER : C_INCOMPLETE;
- if (m_Mode & 0x02)
- {
- LOG(("Single actuator\n"));
- }
- else
- {
- LOG(("Double actuator\n"));
- }
- }
- break;
+ case 0x3d:
+ return command_pos == 2 ? C_READ_SPECIAL_REGISTER : C_INCOMPLETE;
- case I8271_SPECIAL_REGISTER_SURFACE_0_CURRENT_TRACK:
- {
- LOG(("Surface 0 Current Track\n"));
- write_current_track(0, m_CommandParameters[1]);
- }
- break;
-
- case I8271_SPECIAL_REGISTER_SURFACE_1_CURRENT_TRACK:
- {
- LOG(("Surface 1 Current Track\n"));
- write_current_track(1, m_CommandParameters[1]);
- }
- break;
+ default:
+ return C_INVALID;
+ }
+}
- case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_1:
- {
- LOG(("Surface 0 Bad Track 1\n"));
- write_bad_track(0, 1, m_CommandParameters[1]);
- }
- break;
+void i8271_device::start_command(int cmd)
+{
+ command_pos = 0;
+ main_phase = PHASE_EXEC;
+ switch(cmd) {
+ case C_READ_DATA_SINGLE:
+ command[3] = 1;
+ case C_READ_DATA_MULTI:
+ read_data_start(flopi[BIT(command[0], 7)]);
+ break;
- case I8271_SPECIAL_REGISTER_SURFACE_0_BAD_TRACK_2:
- {
- LOG(("Surface 0 Bad Track 2\n"));
- write_bad_track(0, 2,m_CommandParameters[1]);
- }
- break;
+ case C_VERIFY_DATA_SINGLE:
+ command[3] = 1;
+ case C_VERIFY_DATA_MULTI:
+ verify_data_start(flopi[BIT(command[0], 7)]);
+ break;
- case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_1:
- {
- LOG(("Surface 1 Bad Track 1\n"));
+ case C_FORMAT_TRACK:
+ format_track_start(flopi[BIT(command[0], 7)]);
+ break;
+ case C_READ_ID:
+ read_id_start(flopi[BIT(command[0], 7)]);
+ break;
- write_bad_track(1, 1, m_CommandParameters[1]);
- }
- break;
+ case C_SCAN:
+ scan_start(flopi[BIT(command[0], 7)]);
+ break;
- case I8271_SPECIAL_REGISTER_SURFACE_1_BAD_TRACK_2:
- {
- LOG(("Surface 1 Bad Track 2\n"));
+ case C_SEEK:
+ if(!command[1])
+ recalibrate_start(flopi[BIT(command[0], 7)]);
+ else
+ seek_start(flopi[BIT(command[0], 7)]);
+ break;
- write_bad_track(1, 2, m_CommandParameters[1]);
- }
- break;
+ case C_READ_DRIVE_STATUS:
+ {
+ floppy_info &fi = flopi[BIT(command[0], 7)];
+ rr = (get_ready(1) ? 0x40 : 0) | (fi.dev->idx_r() ? 0x10 : 0) | (fi.dev->wpt_r() ? 0 : 8) |
+ (get_ready(0) ? 4 : 0) | (fi.dev->trk00_r() ? 1 : 0);
+ flopi[0].ready = true;
+ flopi[1].ready = true;
+ main_phase = PHASE_IDLE;
+ break;
+ }
+ case C_SPECIFY:
+ logerror("%s: command specify %02x %02x %02x %02x\n",
+ tag(), command[1],
+ command[2], command[3], command[4]);
+ switch(command[1]) {
+ case 0x0d:
+ srate = command[2];
+ hset = command[3];
+ icnt = command[4] >> 4;
+ hload = command[4] & 0xf;
+ break;
+ case 0x10:
+ case 0x18:
+ {
+ floppy_info &fi = flopi[BIT(command[1], 3)];
+ fi.badtrack[0] = command[2];
+ fi.badtrack[1] = command[3];
+ fi.pcn = command[4];
+ }
+ }
+ main_phase = PHASE_IDLE;
+ break;
- case I8271_SPECIAL_REGISTER_DRIVE_CONTROL_OUTPUT_PORT:
- {
-// /* get drive selected */
-// m_drive = (m_CommandParameters[1]>>6) & 0x03;
+ case C_WRITE_DATA_SINGLE:
+ command[3] = 1;
+ case C_WRITE_DATA_MULTI:
+ write_data_start(flopi[BIT(command[0], 7)]);
+ break;
- FDC_LOG_COMMAND("Write Drive Control Output port\n");
+ case C_READ_SPECIAL_REGISTER:
+ switch(command[1] & 0x3f) {
+ case 0x06:
+ rr = scan_sec;
+ break;
+ case 0x10:
+ case 0x11:
+ rr = flopi[0].badtrack[BIT(command[1], 0)];
+ break;
+ case 0x12:
+ rr = flopi[0].pcn;
+ break;
+ case 0x13:
+ rr = scan_cnt[0];
+ break;
+ case 0x14:
+ rr = scan_cnt[1];
+ break;
+ case 0x17:
+ rr = moder;
+ break;
+ case 0x18:
+ case 0x19:
+ rr = flopi[1].badtrack[BIT(command[1], 0)];
+ break;
+ case 0x1a:
+ rr = flopi[1].pcn;
+ break;
+ case 0x22: {
+ floppy_info &fi = flopi[BIT(command[0], 7)];
+ rr = (get_ready(1) ? 0x40 : 0) | (fi.dev->idx_r() ? 0x10 : 0) | (fi.dev->wpt_r() ? 0 : 8) |
+ (get_ready(0) ? 4 : 0) | (fi.dev->trk00_r() ? 1 : 0);
+ break;
+ }
+ case 0x23:
+ rr = (command[0] << 1) & 0xc0;
+ break;
+ default:
+ rr = 0;
+ break;
+ }
+ main_phase = PHASE_IDLE;
+ break;
+ case C_WRITE_SPECIAL_REGISTER:
+ switch(command[1]) {
+ case 0x06:
+ scan_sec = command[2];
+ break;
+ case 0x10:
+ case 0x11:
+ flopi[0].badtrack[BIT(command[1], 0)] = command[2];
+ break;
+ case 0x12:
+ flopi[0].pcn = command[2];
+ break;
+ case 0x13:
+ scan_cnt[0] = command[2];
+ break;
+ case 0x14:
+ scan_cnt[1] = command[2];
+ break;
+ case 0x17:
+ moder = command[2] | 0xc0;
+ break;
+ case 0x18:
+ case 0x19:
+ flopi[1].badtrack[BIT(command[1], 0)] = command[2];
+ break;
+ case 0x1a:
+ flopi[1].pcn = command[2];
+ break;
+ case 0x22:
+ break;
+ case 0x23: {
+ floppy_info &fi = flopi[BIT(command[0], 7)];
+ fi.dev->dir_w(BIT(command[2], 2));
+ fi.dev->stp_w(BIT(command[2], 1));
+ opt_cb(BIT(command[2], 5));
+ hdl_cb(BIT(command[2], 3));
+ break;
+ }
+ }
+ main_phase = PHASE_IDLE;
+ break;
- if (m_CommandParameters[1] & 0x01)
- {
- LOG(("Write Enable\n"));
- }
- if (m_CommandParameters[1] & 0x02)
- {
- LOG(("Seek/Step\n"));
- }
- if (m_CommandParameters[1] & 0x04)
- {
- LOG(("Direction\n"));
- }
- if (m_CommandParameters[1] & 0x08)
- {
- LOG(("Load Head\n"));
- }
- if (m_CommandParameters[1] & 0x010)
- {
- LOG(("Low head current\n"));
- }
- if (m_CommandParameters[1] & 0x020)
- {
- LOG(("Write Fault Reset\n"));
- }
+ default:
+ fprintf(stderr, "start command %d\n", cmd);
+ exit(1);
+ }
+}
- LOG(("Select %02x\n", (m_CommandParameters[1] & 0x0c0)>>6));
+void i8271_device::command_end(floppy_info &fi, bool data_completion)
+{
+ logerror("%s: command done (%s) - %02x\n", tag(), data_completion ? "data" : "seek", rr);
+ fi.main_state = fi.sub_state = IDLE;
+ main_phase = PHASE_RESULT;
+ set_irq(true);
+}
- /* get drive */
- get_drive();
+void i8271_device::recalibrate_start(floppy_info &fi)
+{
+ logerror("%s: command recalibrate\n", tag());
+ fi.main_state = RECALIBRATE;
+ fi.sub_state = SEEK_WAIT_STEP_TIME_DONE;
+ fi.dir = 1;
+ fi.counter = 255;
+ seek_continue(fi);
+}
- /* on bbc dfs 09 this is the side select output */
- m_side = (m_CommandParameters[1]>>5) & 0x01;
+void i8271_device::seek_start(floppy_info &fi)
+{
+ logerror("%s: command seek %d\n", tag(), command[1]);
+ fi.main_state = SEEK;
+ fi.sub_state = SEEK_WAIT_STEP_TIME_DONE;
+ fi.dir = fi.pcn > command[1] ? 1 : 0;
+ seek_continue(fi);
+}
- /* load head - on mini-sized drives this turns on the disc motor,
- on standard-sized drives this loads the head and turns the motor on */
- m_floppy[m_drive]->floppy_mon_w(!BIT(m_CommandParameters[1], 3));
- m_floppy[m_drive]->floppy_drive_set_ready_state(1, 1);
+void i8271_device::delay_cycles(emu_timer *tm, int cycles)
+{
+ tm->adjust(attotime::from_double(double(cycles)/cur_rate));
+}
- /* step pin changed? if so perform a step in the direction indicated */
- if (((m_drive_control_output^m_CommandParameters[1]) & (1<<1))!=0)
- {
- /* step pin changed state? */
-
- if (BIT(m_CommandParameters[1], 1))
- {
- signed int signed_tracks;
-
- if (BIT(m_CommandParameters[1], 2))
- {
- signed_tracks = 1;
- }
- else
- {
- signed_tracks = -1;
- }
-
- m_floppy[m_drive]->floppy_drive_seek(signed_tracks);
- }
- }
+void i8271_device::seek_continue(floppy_info &fi)
+{
+ for(;;) {
+ switch(fi.sub_state) {
+ case SEEK_MOVE:
+ if(fi.dev) {
+ fi.dev->dir_w(fi.dir);
+ fi.dev->stp_w(0);
+ }
+ fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
+ fi.tm->adjust(attotime::from_nsec(2500));
+ return;
- m_drive_control_output = m_CommandParameters[1];
+ case SEEK_WAIT_STEP_SIGNAL_TIME:
+ return;
+ case SEEK_WAIT_STEP_SIGNAL_TIME_DONE:
+ if(fi.dev)
+ fi.dev->stp_w(1);
+ do {
+ if(fi.pcn > command[1])
+ fi.pcn--;
+ else
+ fi.pcn++;
+ } while((fi.pcn == fi.badtrack[0]) || (fi.pcn == fi.badtrack[1]));
+ fi.sub_state = SEEK_WAIT_STEP_TIME;
+ delay_cycles(fi.tm, 500*srate);
+ return;
+
+ case SEEK_WAIT_STEP_TIME:
+ return;
+
+ case SEEK_WAIT_STEP_TIME_DONE: {
+ bool done = false;
+ switch(fi.main_state) {
+ case RECALIBRATE:
+ fi.counter--;
+ done = fi.dev && !fi.dev->trk00_r();
+ if(done)
+ fi.pcn = 0;
+ else if(!fi.counter) {
+ rr = ERR_T0NF;
+ command_end(fi, false);
+ return;
}
break;
-
- case I8271_SPECIAL_REGISTER_DRIVE_CONTROL_INPUT_PORT:
- {
- FDC_LOG_COMMAND("Write Drive Control Input port\n");
-
- // m_drive_control_input = m_CommandParameters[1];
- }
+ case SEEK:
+ done = fi.pcn == command[1];
break;
-
}
-
- /* write doesn't supply a result */
- command_complete(0,0);
+ if(done) {
+ rr = ERR_NONE;
+ command_end(fi, false);
+ return;
+ }
+ fi.sub_state = SEEK_MOVE;
+ break;
}
- break;
-
- case I8271_COMMAND_READ_DRIVE_STATUS:
- {
- unsigned char status;
+ }
+ }
+}
- get_drive();
+void i8271_device::read_data_start(floppy_info &fi)
+{
+ fi.main_state = READ_DATA;
+ fi.sub_state = HEAD_LOAD_DONE;
+
+ logerror("%s: command read%s data%s cmd=%02x crn=(%d, %d, %d) len=%02x rate=%d\n",
+ tag(),
+ command[0] & 0x04 ? " deleted" : "",
+ command[0] & 0x01 ? " multi" : "",
+ command[0],
+ command[1],
+ command[2],
+ calc_sector_size(command[3] >> 5),
+ command[3] & 0x1f,
+ cur_rate);
+
+ rr = ERR_NONE;
+ fi.ready = get_ready(BIT(command[0], 7));
+
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = COMMAND_DONE;
+ read_data_continue(fi);
+ return;
+ }
- /* no write fault */
- status = 0;
+ read_data_continue(fi);
+}
- status |= (1<<2) | (1<<6);
+void i8271_device::scan_start(floppy_info &fi)
+{
+ fi.main_state = SCAN_DATA;
+ fi.sub_state = HEAD_LOAD_DONE;
+
+ logerror("%s: command scan%s data%s cmd=%02x crn=(%d, %d, %d) len=%02x rate=%d\n",
+ tag(),
+ command[0] & 0x04 ? " deleted" : "",
+ command[0] & 0x01 ? " multi" : "",
+ command[0],
+ command[1],
+ command[2],
+ calc_sector_size(command[3] >> 5),
+ command[3] & 0x1f,
+ cur_rate);
+
+ rr = ERR_NONE;
+ scan_done = false;
+ scan_len = 0;
+ scan_match = true;
+ fi.ready = get_ready(BIT(command[0], 7));
+
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = COMMAND_DONE;
+ read_data_continue(fi);
+ return;
+ }
+ read_data_continue(fi);
+}
- /* these two do not appear to be set at all! ?? */
+void i8271_device::verify_data_start(floppy_info &fi)
+{
+ fi.main_state = VERIFY_DATA;
+ fi.sub_state = HEAD_LOAD_DONE;
+
+ logerror("%s: command verify%s data%s cmd=%02x crn=(%d, %d, %d) len=%02x rate=%d\n",
+ tag(),
+ command[0] & 0x04 ? " deleted" : "",
+ command[0] & 0x01 ? " multi" : "",
+ command[0],
+ command[1],
+ command[2],
+ calc_sector_size(command[3] >> 5),
+ command[3] & 0x1f,
+ cur_rate);
+
+ rr = ERR_NONE;
+ fi.ready = get_ready(BIT(command[0], 7));
+
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = COMMAND_DONE;
+ read_data_continue(fi);
+ return;
+ }
+ read_data_continue(fi);
+}
- if (m_floppy[0])
- {
- if (m_floppy[0]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY))
- {
- status |= (1 << 2);
- }
+void i8271_device::read_data_continue(floppy_info &fi)
+{
+ for(;;) {
+ switch(fi.sub_state) {
+ case HEAD_LOAD_DONE:
+ if(fi.pcn == command[1]) {
+ fi.sub_state = SEEK_DONE;
+ break;
}
-
- if (m_floppy[1])
- {
- if (m_floppy[1]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY))
- {
- status |= (1 << 6);
- }
+ if(fi.dev) {
+ fi.dev->dir_w(fi.pcn > command[1] ? 1 : 0);
+ fi.dev->stp_w(0);
}
+ fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
+ fi.tm->adjust(attotime::from_nsec(2500));
+ return;
- /* bit 3 = 1 if write protected */
- status |= !m_floppy[m_drive]->floppy_wpt_r() << 3;
-
- /* bit 1 = 1 if head at track 0 */
- status |= !m_floppy[m_drive]->floppy_tk00_r() << 1;
-
- m_ResultRegister = status;
- command_complete(1,0);
-
- }
- break;
-
- case I8271_COMMAND_SEEK:
- {
- get_drive();
-
- seek_to_track(m_CommandParameters[0]);
+ case SEEK_WAIT_STEP_SIGNAL_TIME:
+ return;
- /* check for bad seek */
- timed_command_complete();
+ case SEEK_WAIT_STEP_SIGNAL_TIME_DONE:
+ if(fi.dev)
+ fi.dev->stp_w(1);
- }
- break;
+ fi.sub_state = SEEK_WAIT_STEP_TIME;
+ delay_cycles(fi.tm, 500*srate);
+ return;
- case I8271_COMMAND_READ_DATA_MULTI_RECORD:
- {
- /* N value as stored in ID field */
- m_ID_N = (m_CommandParameters[2]>>5) & 0x07;
+ case SEEK_WAIT_STEP_TIME:
+ return;
- /* starting sector id */
- m_ID_R = m_CommandParameters[1];
-
- /* number of sectors to transfer */
- m_Counter = m_CommandParameters[2] & 0x01f;
-
-
- FDC_LOG_COMMAND("READ DATA MULTI RECORD");
+ case SEEK_WAIT_STEP_TIME_DONE:
+ do {
+ if(fi.pcn > command[1])
+ fi.pcn--;
+ else
+ fi.pcn++;
+ } while((fi.pcn == fi.badtrack[0]) || (fi.pcn == fi.badtrack[1]));
+ fi.sub_state = HEAD_LOAD_DONE;
+ break;
- LOG(("Sector Count: %02x\n", m_Counter));
- LOG(("Track: %02x\n",m_CommandParameters[0]));
- LOG(("Sector: %02x\n", m_CommandParameters[1]));
- LOG(("Sector Length: %02x bytes\n", 1<<(m_ID_N+7)));
+ case SEEK_DONE:
+ fi.counter = 0;
+ fi.sub_state = SCAN_ID;
+ live_start(fi, SEARCH_ADDRESS_MARK_HEADER);
+ return;
- get_drive();
+ case SCAN_ID:
+ if(cur_live.crc) {
+ rr = ERR_ICRC;
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
+ if(!sector_matches()) {
+ if(cur_live.idbuf[0] != command[1]) {
+ rr = ERR_NF;
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
+ live_start(fi, SEARCH_ADDRESS_MARK_HEADER);
+ return;
+ }
+ logerror("%s: reading sector %02x %02x %02x %02x\n",
+ tag(),
+ cur_live.idbuf[0],
+ cur_live.idbuf[1],
+ cur_live.idbuf[2],
+ cur_live.idbuf[3]);
+ sector_size = calc_sector_size(cur_live.idbuf[3]);
+ fi.sub_state = SECTOR_READ;
+ live_start(fi, SEARCH_ADDRESS_MARK_DATA);
+ return;
+
+ case SCAN_ID_FAILED:
+ rr = ERR_NF;
+ fi.sub_state = COMMAND_DONE;
+ break;
- if (!m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY))
- {
- /* Completion type: operation intervention probably required for recovery */
- /* Completion code: Drive not ready */
- m_ResultRegister = (2<<3);
- timed_command_complete();
+ case SECTOR_READ: {
+ if(cur_live.crc) {
+ rr = ERR_DCRC;
+ fi.sub_state = COMMAND_DONE;
+ break;
}
- else
+ bool done = rr || (!(command[0] & 1) && (fi.main_state != SCAN_DATA));
+ if(!done)
{
- seek_to_track(m_CommandParameters[0]);
-
-
- do_read();
+ command[3] = (command[3] & 0xe0) | ((command[3] & 0x1f) - 1);
+ if(command[3] & 0x1f)
+ command[2]++;
+ else
+ done = true;
}
-
+ if(!done) {
+ fi.sub_state = SEEK_DONE;
+ break;
+ }
+ fi.sub_state = COMMAND_DONE;
+ break;
}
- break;
- case I8271_COMMAND_READ_DATA_SINGLE_RECORD:
- {
- FDC_LOG_COMMAND("READ DATA SINGLE RECORD");
+ case COMMAND_DONE:
+ command_end(fi, true);
+ return;
- m_ID_N = 0;
- m_Counter = 1;
- m_ID_R = m_CommandParameters[1];
+ default:
+ logerror("%s: read sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ return;
+ }
+ }
+}
- LOG(("Sector Count: %02x\n", m_Counter));
- LOG(("Track: %02x\n",m_CommandParameters[0]));
- LOG(("Sector: %02x\n", m_CommandParameters[1]));
- LOG(("Sector Length: %02x bytes\n", 1<<(m_ID_N+7)));
+void i8271_device::write_data_start(floppy_info &fi)
+{
+ fi.main_state = WRITE_DATA;
+ fi.sub_state = HEAD_LOAD_DONE;
+ logerror("%s: command write%s data%s cmd=%02x crn=(%d, %d, %d) len=%02x rate=%d\n",
+ tag(),
+ command[0] & 0x04 ? " deleted" : "",
+ command[0] & 0x01 ? " multi" : "",
+ command[0],
+ command[1],
+ command[2],
+ calc_sector_size(command[3] >> 5),
+ command[3] & 0x1f,
+ cur_rate);
+
+ rr = ERR_NONE;
+ fi.ready = get_ready(BIT(command[0], 7));
+
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = COMMAND_DONE;
+ write_data_continue(fi);
+ return;
+ }
- get_drive();
+ write_data_continue(fi);
+}
- if (!m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY))
- {
- /* Completion type: operation intervention probably required for recovery */
- /* Completion code: Drive not ready */
- m_ResultRegister = (2<<3);
- timed_command_complete();
+void i8271_device::write_data_continue(floppy_info &fi)
+{
+ for(;;) {
+ switch(fi.sub_state) {
+ case HEAD_LOAD_DONE:
+ if(fi.pcn == command[1]) {
+ fi.sub_state = SEEK_DONE;
+ break;
}
- else
- {
- seek_to_track(m_CommandParameters[0]);
-
- do_read();
+ if(fi.dev) {
+ fi.dev->dir_w(fi.pcn > command[1] ? 1 : 0);
+ fi.dev->stp_w(0);
}
+ fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
+ fi.tm->adjust(attotime::from_nsec(2500));
+ return;
- }
- break;
-
- case I8271_COMMAND_WRITE_DATA_MULTI_RECORD:
- {
- /* N value as stored in ID field */
- m_ID_N = (m_CommandParameters[2]>>5) & 0x07;
-
- /* starting sector id */
- m_ID_R = m_CommandParameters[1];
+ case SEEK_WAIT_STEP_SIGNAL_TIME:
+ return;
- /* number of sectors to transfer */
- m_Counter = m_CommandParameters[2] & 0x01f;
+ case SEEK_WAIT_STEP_SIGNAL_TIME_DONE:
+ if(fi.dev)
+ fi.dev->stp_w(1);
- FDC_LOG_COMMAND("READ DATA MULTI RECORD");
+ fi.sub_state = SEEK_WAIT_STEP_TIME;
+ delay_cycles(fi.tm, 500*srate);
+ return;
- LOG(("Sector Count: %02x\n", m_Counter));
- LOG(("Track: %02x\n",m_CommandParameters[0]));
- LOG(("Sector: %02x\n", m_CommandParameters[1]));
- LOG(("Sector Length: %02x bytes\n", 1<<(m_ID_N+7)));
+ case SEEK_WAIT_STEP_TIME:
+ return;
- get_drive();
+ case SEEK_WAIT_STEP_TIME_DONE:
+ do {
+ if(fi.pcn > command[1])
+ fi.pcn--;
+ else
+ fi.pcn++;
+ } while((fi.pcn == fi.badtrack[0]) || (fi.pcn == fi.badtrack[1]));
+ fi.sub_state = HEAD_LOAD_DONE;
+ break;
- m_drive_control_output &=~1;
+ case SEEK_DONE:
+ fi.counter = 0;
+ fi.sub_state = SCAN_ID;
+ live_start(fi, SEARCH_ADDRESS_MARK_HEADER);
+ return;
- if (!m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY))
- {
- /* Completion type: operation intervention probably required for recovery */
- /* Completion code: Drive not ready */
- m_ResultRegister = (2<<3);
- timed_command_complete();
+ case SCAN_ID:
+ if(!sector_matches()) {
+ live_start(fi, SEARCH_ADDRESS_MARK_HEADER);
+ return;
}
- else
+ if(cur_live.crc) {
+ rr = ERR_ICRC;
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
+ sector_size = calc_sector_size(cur_live.idbuf[3]);
+ fi.sub_state = SECTOR_WRITTEN;
+ set_drq(true);
+ live_start(fi, WRITE_SECTOR_SKIP_GAP2);
+ return;
+
+ case SCAN_ID_FAILED:
+ rr = ERR_NF;
+ fi.sub_state = COMMAND_DONE;
+ break;
+
+ case SECTOR_WRITTEN: {
+ bool done = rr || !(command[0] & 1);
+ if(!done)
{
- if (m_floppy[m_drive]->floppy_wpt_r() == CLEAR_LINE)
- {
- /* Completion type: operation intervention probably required for recovery */
- /* Completion code: Drive write protected */
- m_ResultRegister = (2<<3) | (1<<1);
- timed_command_complete();
- }
+ command[3] = (command[3] & 0xe0) | ((command[3] & 0x1f) - 1);
+ if(command[3] & 0x1f)
+ command[2]++;
else
- {
- m_drive_control_output |=1;
+ done = true;
+ }
+ if(!done) {
+ fi.sub_state = HEAD_LOAD_DONE;
+ break;
+ }
+ fi.sub_state = COMMAND_DONE;
+ break;
+ }
- seek_to_track(m_CommandParameters[0]);
+ case COMMAND_DONE:
+ command_end(fi, true);
+ return;
- do_write();
- }
- }
+ default:
+ logerror("%s: write sector unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ return;
}
- break;
+ }
+}
- case I8271_COMMAND_WRITE_DATA_SINGLE_RECORD:
- {
- FDC_LOG_COMMAND("WRITE DATA SINGLE RECORD");
+int i8271_device::calc_sector_size(UINT8 size)
+{
+ return size > 7 ? 16384 : 128 << size;
+}
- m_ID_N = 0;
- m_Counter = 1;
- m_ID_R = m_CommandParameters[1];
+void i8271_device::format_track_start(floppy_info &fi)
+{
+ fi.main_state = FORMAT_TRACK;
+ fi.sub_state = HEAD_LOAD_DONE;
+ logerror("%s: command format track c=%02x n=%02x sc=%02x gap3=%02x gap5=%02x gap1=%02x\n",
+ tag(),
+ command[1], command[3] >> 5, command[3] & 0x1f, command[2], command[4], command[5]);
- LOG(("Sector Count: %02x\n", m_Counter));
- LOG(("Track: %02x\n",m_CommandParameters[0]));
- LOG(("Sector: %02x\n", m_CommandParameters[1]));
- LOG(("Sector Length: %02x bytes\n", 1<<(m_ID_N+7)));
- get_drive();
+ rr = ERR_NONE;
- m_drive_control_output &=~1;
+ fi.ready = get_ready(BIT(command[0], 7));
- if (!m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY))
- {
- /* Completion type: operation intervention probably required for recovery */
- /* Completion code: Drive not ready */
- m_ResultRegister = (2<<3);
- timed_command_complete();
- }
- else
- {
- if (m_floppy[m_drive]->floppy_wpt_r() == CLEAR_LINE)
- {
- /* Completion type: operation intervention probably required for recovery */
- /* Completion code: Drive write protected */
- m_ResultRegister = (2<<3) | (1<<1);
- timed_command_complete();
- }
- else
- {
- m_drive_control_output |=1;
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = TRACK_DONE;
+ format_track_continue(fi);
+ return;
+ }
+ sector_size = calc_sector_size(command[3] >> 5);
- seek_to_track(m_CommandParameters[0]);
+ format_track_continue(fi);
+}
- do_write();
- }
+void i8271_device::format_track_continue(floppy_info &fi)
+{
+ for(;;) {
+ switch(fi.sub_state) {
+ case HEAD_LOAD_DONE:
+ if(fi.pcn == command[1]) {
+ fi.sub_state = WAIT_INDEX;
+ break;
}
+ if(fi.dev) {
+ fi.dev->dir_w(fi.pcn > command[1] ? 1 : 0);
+ fi.dev->stp_w(0);
+ }
+ fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
+ fi.tm->adjust(attotime::from_nsec(2500));
+ return;
- }
- break;
+ case SEEK_WAIT_STEP_SIGNAL_TIME:
+ return;
+ case SEEK_WAIT_STEP_SIGNAL_TIME_DONE:
+ if(fi.dev)
+ fi.dev->stp_w(1);
- case I8271_COMMAND_READ_ID:
- {
- FDC_LOG_COMMAND("READ ID");
+ fi.sub_state = SEEK_WAIT_STEP_TIME;
+ delay_cycles(fi.tm, 500*srate);
+ return;
- LOG(("Track: %02x\n",m_CommandParameters[0]));
- LOG(("ID Field Count: %02x\n", m_CommandParameters[2]));
+ case SEEK_WAIT_STEP_TIME:
+ return;
- get_drive();
+ case SEEK_WAIT_STEP_TIME_DONE:
+ do {
+ if(fi.pcn > command[1])
+ fi.pcn--;
+ else
+ fi.pcn++;
+ } while((fi.pcn == fi.badtrack[0]) || (fi.pcn == fi.badtrack[1]));
+ fi.sub_state = HEAD_LOAD_DONE;
+ break;
- if (!m_floppy[m_drive]->floppy_drive_get_flag_state(FLOPPY_DRIVE_READY))
- {
- /* Completion type: operation intervention probably required for recovery */
- /* Completion code: Drive not ready */
- m_ResultRegister = (2<<3);
- timed_command_complete();
- }
- else
- {
- m_Counter = m_CommandParameters[2];
+ case SEEK_DONE:
+ fi.sub_state = WAIT_INDEX;
+ break;
- seek_to_track(m_CommandParameters[0]);
+ case WAIT_INDEX:
+ return;
- do_read_id();
- }
- }
- break;
+ case WAIT_INDEX_DONE:
+ logerror("%s: index found, writing track\n", tag());
+ fi.sub_state = TRACK_DONE;
+ cur_live.pll.start_writing(machine().time());
+ set_drq(true);
+ live_start(fi, WRITE_TRACK_PRE_SECTORS);
+ return;
+
+ case TRACK_DONE:
+ command_end(fi, true);
+ return;
default:
- LOG(("ERROR Unrecognised Command\n"));
- break;
+ logerror("%s: format track unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ return;
+ }
}
}
-
-
-WRITE8_MEMBER(i8271_device::write)
+void i8271_device::read_id_start(floppy_info &fi)
{
- switch (offset & 3)
- {
- case 0:
- {
- LOG(("I8271 W Command Register: %02x\n", data));
+ fi.main_state = READ_ID;
+ fi.sub_state = HEAD_LOAD_DONE;
- m_CommandRegister = data;
- m_Command = m_CommandRegister & 0x03f;
+ logerror("%s: command read id, rate=%d\n",
+ tag(),
+ cur_rate);
- m_StatusRegister |= I8271_STATUS_COMMAND_BUSY | I8271_STATUS_COMMAND_FULL;
- m_StatusRegister &= ~I8271_STATUS_PARAMETER_FULL | I8271_STATUS_RESULT_FULL;
- m_ParameterCountWritten = 0;
+ rr = ERR_NONE;
- switch (m_Command)
- {
- case I8271_COMMAND_SPECIFY:
- {
- FDC_LOG_COMMAND("SPECIFY");
+ for(int i=0; i<4; i++)
+ cur_live.idbuf[i] = 0x00;
- m_ParameterCount = 4;
- }
- break;
+ fi.ready = get_ready(command[1] & 3);
- case I8271_COMMAND_SEEK:
- {
- FDC_LOG_COMMAND("SEEK");
-
- m_ParameterCount = 1;
- }
- break;
-
- case I8271_COMMAND_READ_DRIVE_STATUS:
- {
- FDC_LOG_COMMAND("READ DRIVE STATUS");
-
- m_ParameterCount = 0;
- }
- break;
-
- case I8271_COMMAND_READ_SPECIAL_REGISTER:
- {
- FDC_LOG_COMMAND("READ SPECIAL REGISTER");
-
- m_ParameterCount = 1;
- }
- break;
+ if(!fi.ready) {
+ rr = ERR_NR;
+ fi.sub_state = COMMAND_DONE;
+ read_id_continue(fi);
+ return;
+ }
- case I8271_COMMAND_WRITE_SPECIAL_REGISTER:
- {
- FDC_LOG_COMMAND("WRITE SPECIAL REGISTER");
+ read_id_continue(fi);
+}
- m_ParameterCount = 2;
- }
+void i8271_device::read_id_continue(floppy_info &fi)
+{
+ for(;;) {
+ switch(fi.sub_state) {
+ case HEAD_LOAD_DONE:
+ if(fi.pcn == command[1]) {
+ fi.sub_state = SEEK_DONE;
break;
+ }
+ if(fi.dev) {
+ fi.dev->dir_w(fi.pcn > command[1] ? 1 : 0);
+ fi.dev->stp_w(0);
+ }
+ fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME;
+ fi.tm->adjust(attotime::from_nsec(2500));
+ return;
- case I8271_COMMAND_FORMAT:
- {
- m_ParameterCount = 5;
- }
- break;
+ case SEEK_WAIT_STEP_SIGNAL_TIME:
+ return;
- case I8271_COMMAND_READ_ID:
- {
- m_ParameterCount = 3;
+ case SEEK_WAIT_STEP_SIGNAL_TIME_DONE:
+ if(fi.dev)
+ fi.dev->stp_w(1);
- }
- break;
+ fi.sub_state = SEEK_WAIT_STEP_TIME;
+ delay_cycles(fi.tm, 500*srate);
+ return;
+ case SEEK_WAIT_STEP_TIME:
+ return;
- case I8271_COMMAND_READ_DATA_SINGLE_RECORD:
- case I8271_COMMAND_READ_DATA_AND_DELETED_DATA_SINGLE_RECORD:
- case I8271_COMMAND_WRITE_DATA_SINGLE_RECORD:
- case I8271_COMMAND_WRITE_DELETED_DATA_SINGLE_RECORD:
- case I8271_COMMAND_VERIFY_DATA_AND_DELETED_DATA_SINGLE_RECORD:
- {
- m_ParameterCount = 2;
- }
- break;
+ case SEEK_WAIT_STEP_TIME_DONE:
+ do {
+ if(fi.pcn > command[1])
+ fi.pcn--;
+ else
+ fi.pcn++;
+ } while((fi.pcn == fi.badtrack[0]) || (fi.pcn == fi.badtrack[1]));
+ fi.sub_state = HEAD_LOAD_DONE;
+ break;
- case I8271_COMMAND_READ_DATA_MULTI_RECORD:
- case I8271_COMMAND_READ_DATA_AND_DELETED_DATA_MULTI_RECORD:
- case I8271_COMMAND_WRITE_DATA_MULTI_RECORD:
- case I8271_COMMAND_WRITE_DELETED_DATA_MULTI_RECORD:
- case I8271_COMMAND_VERIFY_DATA_AND_DELETED_DATA_MULTI_RECORD:
- {
- m_ParameterCount = 3;
- }
- break;
+ case SEEK_DONE:
+ fi.counter = 0;
+ fi.sub_state = SCAN_ID;
+ live_start(fi, SEARCH_ADDRESS_MARK_HEADER);
+ return;
- case I8271_COMMAND_SCAN_DATA:
- case I8271_COMMAND_SCAN_DATA_AND_DELETED_DATA:
- {
- m_ParameterCount = 5;
- }
+ case SCAN_ID:
+ if(cur_live.crc) {
+ rr = ERR_ICRC;
+ fi.sub_state = COMMAND_DONE;
break;
+ }
+ if(!(command[3]--)) {
+ fi.counter = 0;
+ fi.sub_state = SCAN_ID;
+ }
+ else
+ fi.sub_state = COMMAND_DONE;
+ break;
+ case SCAN_ID_FAILED:
+ if(rr != ERR_DMA)
+ rr = ERR_NF;
+ fi.sub_state = COMMAND_DONE;
+ break;
+ case COMMAND_DONE:
+ command_end(fi, true);
+ return;
+ default:
+ logerror("%s: read id unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
+ return;
+ }
+ }
+}
+std::string i8271_device::tts(attotime t)
+{
+ char buf[256];
+ const char *sign = "";
+ if(t.seconds() < 0) {
+ t = attotime::zero-t;
+ sign = "-";
+ }
+ int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
+ sprintf(buf, "%s%04d.%03d,%03d,%03d", sign, int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
+ return buf;
+}
+std::string i8271_device::ttsn()
+{
+ return tts(machine().time());
+}
- }
+void i8271_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ live_sync();
- check_all_parameters_written();
- }
+ floppy_info &fi = flopi[id];
+ switch(fi.sub_state) {
+ case SEEK_WAIT_STEP_SIGNAL_TIME:
+ fi.sub_state = SEEK_WAIT_STEP_SIGNAL_TIME_DONE;
break;
+ case SEEK_WAIT_STEP_TIME:
+ fi.sub_state = SEEK_WAIT_STEP_TIME_DONE;
+ break;
+ }
- case 1:
- {
- LOG(("I8271 W Parameter Register: %02x\n",data));
- m_ParameterRegister = data;
-
- if (m_ParameterCount!=0)
- {
- m_CommandParameters[m_ParameterCountWritten] = data;
- m_ParameterCountWritten++;
- }
+ general_continue(fi);
+}
- check_all_parameters_written();
+void i8271_device::index_callback(floppy_image_device *floppy, int state)
+{
+ for(int fid=0; fid<2; fid++) {
+ floppy_info &fi = flopi[fid];
+ if(fi.dev != floppy)
+ continue;
+
+ if(fi.live)
+ live_sync();
+ fi.index = state;
+
+ if(!state) {
+ general_continue(fi);
+ continue;
}
- break;
- case 2:
- {
- LOG(("I8271 W Reset Register: %02x\n", data));
- if (((data ^ m_ResetRegister) & 0x01)!=0)
- {
- if ((data & 0x01)==0)
- {
- reset();
- }
- }
+ switch(fi.sub_state) {
+ case IDLE:
+ case SEEK_MOVE:
+ case SEEK_WAIT_STEP_SIGNAL_TIME:
+ case SEEK_WAIT_STEP_SIGNAL_TIME_DONE:
+ case SEEK_WAIT_STEP_TIME:
+ case SEEK_WAIT_STEP_TIME_DONE:
+ case HEAD_LOAD_DONE:
+ case SCAN_ID_FAILED:
+ case SECTOR_READ:
+ break;
- m_ResetRegister = data;
+ case WAIT_INDEX:
+ fi.sub_state = WAIT_INDEX_DONE;
+ break;
+ case SCAN_ID:
+ fi.counter++;
+ if(fi.counter == 2) {
+ fi.sub_state = SCAN_ID_FAILED;
+ live_abort();
+ }
+ break;
- }
- break;
+ case TRACK_DONE:
+ live_abort();
+ break;
default:
+ logerror("%s: Index pulse on unknown sub-state %d\n", ttsn().c_str(), fi.sub_state);
break;
+ }
+
+ general_continue(fi);
}
}
-READ8_MEMBER(i8271_device::read)
+
+void i8271_device::general_continue(floppy_info &fi)
{
- switch (offset & 3)
- {
- case 0:
- {
- /* bit 1,0 are zero other bits contain status data */
- m_StatusRegister &= ~0x03;
- LOG(("I8271 R Status Register: %02x\n",m_StatusRegister));
- return m_StatusRegister;
- }
+ if(fi.live && cur_live.state != IDLE) {
+ live_run();
+ if(cur_live.state != IDLE)
+ return;
+ }
- case 1:
- {
- if ((m_StatusRegister & I8271_STATUS_COMMAND_BUSY)==0)
- {
- /* clear IRQ */
- set_irq_state(0);
+ switch(fi.main_state) {
+ case IDLE:
+ break;
- m_StatusRegister &= ~I8271_STATUS_RESULT_FULL;
- LOG(("I8271 R Result Register %02x\n",m_ResultRegister));
- return m_ResultRegister;
- }
+ case RECALIBRATE:
+ case SEEK:
+ seek_continue(fi);
+ break;
- /* not useful information when command busy */
- return 0x0ff;
- }
+ case READ_DATA:
+ case SCAN_DATA:
+ case VERIFY_DATA:
+ read_data_continue(fi);
+ break;
+ case WRITE_DATA:
+ write_data_continue(fi);
+ break;
- default:
- break;
- }
+ case FORMAT_TRACK:
+ format_track_continue(fi);
+ break;
- return 0x0ff;
-}
+ case READ_ID:
+ read_id_continue(fi);
+ break;
+ default:
+ logerror("%s: general_continue on unknown main-state %d\n", ttsn().c_str(), fi.main_state);
+ break;
+ }
+}
-/* to be completed! */
-READ8_MEMBER(i8271_device::dack_r)
+bool i8271_device::read_one_bit(const attotime &limit)
{
- return data_r(space, offset);
+ int bit = cur_live.pll.get_next_bit(cur_live.tm, cur_live.fi->dev, limit);
+ if(bit < 0)
+ return true;
+ cur_live.shift_reg = (cur_live.shift_reg << 1) | bit;
+ cur_live.bit_counter++;
+ if(cur_live.data_separator_phase) {
+ cur_live.data_reg = (cur_live.data_reg << 1) | bit;
+ if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000)
+ cur_live.crc = (cur_live.crc << 1) ^ 0x1021;
+ else
+ cur_live.crc = cur_live.crc << 1;
+ }
+ cur_live.data_separator_phase = !cur_live.data_separator_phase;
+ return false;
}
-/* to be completed! */
-WRITE8_MEMBER(i8271_device::dack_w)
+bool i8271_device::write_one_bit(const attotime &limit)
{
- data_w(space, offset, data);
+ bool bit = cur_live.shift_reg & 0x8000;
+ if(cur_live.pll.write_next_bit(bit, cur_live.tm, cur_live.fi->dev, limit))
+ return true;
+ if(cur_live.bit_counter & 1) {
+ if((cur_live.crc ^ (bit ? 0x8000 : 0x0000)) & 0x8000)
+ cur_live.crc = (cur_live.crc << 1) ^ 0x1021;
+ else
+ cur_live.crc = cur_live.crc << 1;
+ }
+ cur_live.shift_reg = cur_live.shift_reg << 1;
+ cur_live.bit_counter--;
+ return false;
}
-READ8_MEMBER(i8271_device::data_r)
+void i8271_device::live_write_raw(UINT16 raw)
{
- clear_data_request();
-
- update_state();
-
- // logerror("I8271 R data: %02x\n",m_data);
-
-
- return m_data;
+ // logerror("write %04x %04x\n", raw, cur_live.crc);
+ cur_live.shift_reg = raw;
+ cur_live.data_bit_context = raw & 1;
}
-WRITE8_MEMBER(i8271_device::data_w)
+void i8271_device::live_write_fm(UINT8 fm)
{
- m_data = data;
-
-// logerror("I8271 W data: %02x\n",m_data);
-
- clear_data_request();
+ UINT16 raw = 0xaaaa;
+ for(int i=0; i<8; i++)
+ if(fm & (0x80 >> i))
+ raw |= 0x4000 >> (2*i);
+ cur_live.data_reg = fm;
+ cur_live.shift_reg = raw;
+ cur_live.data_bit_context = fm & 1;
+ // logerror("write %02x %04x %04x\n", fm, cur_live.crc, raw);
+}
- update_state();
+bool i8271_device::sector_matches() const
+{
+ if(0)
+ logerror("%s: matching %02x %02x %02x - %02x %02x %02x\n", tag(),
+ cur_live.idbuf[0], cur_live.idbuf[2], cur_live.idbuf[3],
+ command[1], command[2], command[3] >> 5);
+ return
+ cur_live.idbuf[0] == command[1] &&
+ cur_live.idbuf[2] == command[2] &&
+ cur_live.idbuf[3] == (command[3] >> 5);
}
diff --git a/src/devices/machine/i8271.h b/src/devices/machine/i8271.h
index c73fb4b680c..4a6fdab7ff8 100644
--- a/src/devices/machine/i8271.h
+++ b/src/devices/machine/i8271.h
@@ -1,24 +1,23 @@
// license:BSD-3-Clause
-// copyright-holders:Kevin Thacker
-/*****************************************************************************
- *
- * machine/i8271.h
- *
- ****************************************************************************/
+// copyright-holders:Carl,Olivier Galibert
+#ifndef I8271N_H_
+#define I8271N_H_
-#ifndef I8271_H_
-#define I8271_H_
-
-#include "imagedev/flopdrv.h"
+#include "emu.h"
+#include "imagedev/floppy.h"
+#include "fdc_pll.h"
#define MCFG_I8271_IRQ_CALLBACK(_write) \
- devcb = &i8271_device::set_irq_wr_callback(*device, DEVCB_##_write);
+ devcb = &i8271_device::set_intrq_wr_callback(*device, DEVCB_##_write);
#define MCFG_I8271_DRQ_CALLBACK(_write) \
devcb = &i8271_device::set_drq_wr_callback(*device, DEVCB_##_write);
-#define MCFG_I8271_FLOPPIES(_tag1, _tag2) \
- i8271_device::set_floppy_tags(*device, _tag1, _tag2);
+#define MCFG_I8271_HDL_CALLBACK(_write) \
+ devcb = &i8271_device::set_hdl_wr_callback(*device, DEVCB_##_write);
+
+#define MCFG_I8271_OPT_CALLBACK(_write) \
+ devcb = &i8271_device::set_opt_wr_callback(*device, DEVCB_##_write);
/***************************************************************************
MACROS
@@ -30,136 +29,268 @@ public:
i8271_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
~i8271_device() {}
- template<class _Object> static devcb_base &set_irq_wr_callback(device_t &device, _Object object) { return downcast<i8271_device &>(device).m_write_irq.set_callback(object); }
- template<class _Object> static devcb_base &set_drq_wr_callback(device_t &device, _Object object) { return downcast<i8271_device &>(device).m_write_drq.set_callback(object); }
-
- static void set_floppy_tags(device_t &device, const char *tag1, const char *tag2)
- {
- i8271_device &dev = downcast<i8271_device &>(device);
- dev.m_floppy_tag1 = tag1;
- dev.m_floppy_tag2 = tag2;
- }
+ template<class _Object> static devcb_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast<i8271_device &>(device).intrq_cb.set_callback(object); }
+ template<class _Object> static devcb_base &set_drq_wr_callback(device_t &device, _Object object) { return downcast<i8271_device &>(device).drq_cb.set_callback(object); }
+ template<class _Object> static devcb_base &set_hdl_wr_callback(device_t &device, _Object object) { return downcast<i8271_device &>(device).hdl_cb.set_callback(object); }
+ template<class _Object> static devcb_base &set_opt_wr_callback(device_t &device, _Object object) { return downcast<i8271_device &>(device).opt_cb.set_callback(object); }
+
+ DECLARE_READ8_MEMBER (sr_r);
+ DECLARE_READ8_MEMBER (rr_r);
+ DECLARE_WRITE8_MEMBER(reset_w) { if(data == 1) soft_reset(); }
+ DECLARE_WRITE8_MEMBER(cmd_w);
+ DECLARE_WRITE8_MEMBER(param_w);
+ DECLARE_READ8_MEMBER (data_r);
+ DECLARE_WRITE8_MEMBER(data_w);
+ DECLARE_ADDRESS_MAP(map, 8);
- DECLARE_READ8_MEMBER(read);
- DECLARE_WRITE8_MEMBER(write);
+ void ready_w(bool val);
- DECLARE_READ8_MEMBER(dack_r);
- DECLARE_WRITE8_MEMBER(dack_w);
+ void set_rate(int rate); // rate in bps, to be used when the fdc is externally frequency-controlled
- DECLARE_READ8_MEMBER(data_r);
- DECLARE_WRITE8_MEMBER(data_w);
+ void set_ready_line_connected(bool ready);
+ void set_select_lines_connected(bool select);
+ void set_floppy(floppy_image_device *image);
+ void soft_reset();
protected:
- // device-level overrides
virtual void device_start();
virtual void device_reset();
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
private:
- // internal state
- enum
- {
- TIMER_DATA_CALLBACK,
- TIMER_TIMED_COMMAND_COMPLETE
+ enum {
+ PHASE_IDLE, PHASE_CMD, PHASE_EXEC, PHASE_RESULT
+ };
+
+ enum {
+ RR_DEL = 0x20,
+ RR_CT = 0x18,
+ RR_CC = 0x06,
+
+ SR_BSY = 0x80,
+ SR_CF = 0x40,
+ SR_PF = 0x20,
+ SR_RF = 0x10,
+ SR_IRQ = 0x08,
+ SR_DRQ = 0x04
+ };
+
+ enum {
+ ERR_NONE = 0x00,
+ ERR_SMEQ = 0x02,
+ ERR_SMNE = 0x04,
+ ERR_CLK = 0x08,
+ ERR_DMA = 0x0a,
+ ERR_ICRC = 0x0c,
+ ERR_DCRC = 0x0e,
+ ERR_NR = 0x10,
+ ERR_WP = 0x12,
+ ERR_T0NF = 0x14,
+ ERR_WF = 0x16,
+ ERR_NF = 0x18
+ };
+
+ enum {
+ // General "doing nothing" state
+ IDLE,
+
+ // Main states
+ RECALIBRATE,
+ SEEK,
+ READ_DATA,
+ WRITE_DATA,
+ FORMAT_TRACK,
+ READ_ID,
+ SCAN_DATA,
+ VERIFY_DATA,
+
+ // Sub-states
+ COMMAND_DONE,
+
+ SEEK_MOVE,
+ SEEK_WAIT_STEP_SIGNAL_TIME,
+ SEEK_WAIT_STEP_SIGNAL_TIME_DONE,
+ SEEK_WAIT_STEP_TIME,
+ SEEK_WAIT_STEP_TIME_DONE,
+ SEEK_DONE,
+
+ HEAD_LOAD_DONE,
+
+ WAIT_INDEX,
+ WAIT_INDEX_DONE,
+
+ SCAN_ID,
+ SCAN_ID_FAILED,
+
+ SECTOR_READ,
+ SECTOR_WRITTEN,
+ TC_DONE,
+
+ TRACK_DONE,
+
+ // Live states
+ SEARCH_ADDRESS_MARK_HEADER,
+ READ_ID_BLOCK,
+ SEARCH_ADDRESS_MARK_DATA,
+ SEARCH_ADDRESS_MARK_DATA_FAILED,
+ READ_SECTOR_DATA,
+ READ_SECTOR_DATA_BYTE,
+ SCAN_SECTOR_DATA_BYTE,
+ VERIFY_SECTOR_DATA_BYTE,
+
+ WRITE_SECTOR_SKIP_GAP2,
+ WRITE_SECTOR_SKIP_GAP2_BYTE,
+ WRITE_SECTOR_DATA,
+ WRITE_SECTOR_DATA_BYTE,
+
+ WRITE_TRACK_PRE_SECTORS,
+ WRITE_TRACK_PRE_SECTORS_BYTE,
+
+ WRITE_TRACK_SECTOR,
+ WRITE_TRACK_SECTOR_BYTE,
+
+ WRITE_TRACK_POST_SECTORS,
+ WRITE_TRACK_POST_SECTORS_BYTE
+ };
+
+ struct pll_t {
+ attotime ctime, period, min_period, max_period, period_adjust_base, phase_adjust;
+
+ attotime write_start_time;
+ attotime write_buffer[32];
+ int write_position;
+ int freq_hist;
+
+ void set_clock(const attotime &period);
+ void reset(const attotime &when);
+ int get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit);
+ bool write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit);
+ void start_writing(const attotime &tm);
+ void commit(floppy_image_device *floppy, const attotime &tm);
+ void stop_writing(floppy_image_device *floppy, const attotime &tm);
+ };
+
+ struct floppy_info {
+ enum { IRQ_NONE, IRQ_POLLED, IRQ_SEEK, IRQ_DONE };
+ emu_timer *tm;
+ floppy_image_device *dev;
+ int id;
+ int main_state, sub_state;
+ int dir, counter;
+ UINT8 pcn, badtrack[2];
+ bool live, index, ready;
};
- devcb_write_line m_write_irq;
- devcb_write_line m_write_drq;
-
- const char *m_floppy_tag1, *m_floppy_tag2;
- legacy_floppy_image_device *m_floppy[2];
-
- int m_flags;
- int m_state;
- unsigned char m_Command;
- unsigned char m_StatusRegister;
- unsigned char m_CommandRegister;
- unsigned char m_ResultRegister;
- unsigned char m_ParameterRegister;
- unsigned char m_ResetRegister;
- unsigned char m_data;
-
- /* number of parameters required after command is specified */
- unsigned long m_ParameterCount;
- /* number of parameters written so far */
- unsigned long m_ParameterCountWritten;
-
- unsigned char m_CommandParameters[8];
-
- /* current track for each drive */
- unsigned long m_CurrentTrack[2];
-
- /* 2 bad tracks for drive 0, followed by 2 bad tracks for drive 1 */
- unsigned long m_BadTracks[4];
-
- /* mode special register */
- unsigned long m_Mode;
-
-
- /* drive outputs */
- int m_drive;
- int m_side;
-
- /* drive control output special register */
- int m_drive_control_output;
- /* drive control input special register */
- int m_drive_control_input;
-
- unsigned long m_StepRate;
- unsigned long m_HeadSettlingTime;
- unsigned long m_IndexCountBeforeHeadUnload;
- unsigned long m_HeadLoadTime;
-
- /* id on disc to find */
- //int m_ID_C;
- //int m_ID_H;
- int m_ID_R;
- int m_ID_N;
-
- /* id of data for read/write */
- int m_data_id;
-
- int m_ExecutionPhaseTransferCount;
- char *m_pExecutionPhaseData;
- int m_ExecutionPhaseCount;
-
- /* sector counter and id counter */
- int m_Counter;
-
- /* ==0, to cpu, !=0 =from cpu */
- //int m_data_direction;
-
- emu_timer *m_data_timer;
- emu_timer *m_command_complete_timer;
-
- void seek_to_track(int track);
- void load_bad_tracks(int surface);
- void write_bad_track(int surface, int track, int data);
- void write_current_track(int surface, int track);
- int read_current_track(int surface);
- int read_bad_track(int surface, int track);
- void get_drive();
- void check_all_parameters_written();
- void update_state();
- void initialise_execution_phase_read(int transfer_size);
- void initialise_execution_phase_write(int transfer_size);
- void command_execute();
- void command_continue();
- void command_complete(int result, int int_rq);
- void timed_command_complete();
- void data_request();
- void clear_data_request();
- void timed_data_request();
- /* locate sector for read/write operation */
- int find_sector();
- /* do a read operation */
- void do_read();
- void do_write();
- void do_read_id();
- void set_irq_state(int);
- void set_dma_drq();
+ struct live_info {
+ enum { PT_NONE, PT_CRC_1, PT_CRC_2 };
+
+ attotime tm;
+ int state, next_state;
+ floppy_info *fi;
+ UINT16 shift_reg;
+ UINT16 crc;
+ int bit_counter, byte_counter, previous_type;
+ bool data_separator_phase, data_bit_context;
+ UINT8 data_reg;
+ UINT8 idbuf[6];
+ fdc_pll_t pll;
+ };
+
+ bool ready_connected, select_connected;
+
+ bool external_ready;
+
+ int mode;
+ int main_phase;
+
+ live_info cur_live, checkpoint_live;
+ devcb_write_line intrq_cb, drq_cb, hdl_cb, opt_cb;
+ bool irq, drq, scan_done, scan_match;
+ floppy_info flopi[2];
+
+ int command_pos, sectors_read, scan_len;
+ UINT8 command[6], dma_data;
+ UINT8 rr, scan_sec, moder;
+ UINT8 precomp, perpmode, scan_cnt[2];
+ UINT8 srate, hset, icnt, hload;
+ int sector_size;
+ int cur_rate;
+
+ static std::string tts(attotime t);
+ std::string ttsn();
+
+ enum {
+ C_FORMAT_TRACK,
+ C_READ_DATA_SINGLE,
+ C_READ_DATA_MULTI,
+ C_VERIFY_DATA_SINGLE,
+ C_VERIFY_DATA_MULTI,
+ C_WRITE_DATA_SINGLE,
+ C_WRITE_DATA_MULTI,
+ C_READ_ID,
+ C_SEEK,
+ C_READ_DRIVE_STATUS,
+ C_SPECIFY,
+ C_SCAN,
+ C_WRITE_SPECIAL_REGISTER,
+ C_READ_SPECIAL_REGISTER,
+
+ C_INVALID,
+ C_INCOMPLETE
+ };
+
+ void delay_cycles(emu_timer *tm, int cycles);
+ void set_drq(bool state);
+ void set_irq(bool state);
+ bool get_ready(int fid);
+
+ void enable_transfer();
+ void disable_transfer();
+ int calc_sector_size(UINT8 size);
+
+ int check_command();
+ void start_command(int cmd);
+ void command_end(floppy_info &fi, bool data_completion);
+
+ void recalibrate_start(floppy_info &fi);
+ void seek_start(floppy_info &fi);
+ void seek_continue(floppy_info &fi);
+
+ void read_data_start(floppy_info &fi);
+ void read_data_continue(floppy_info &fi);
+
+ void write_data_start(floppy_info &fi);
+ void write_data_continue(floppy_info &fi);
+
+ void format_track_start(floppy_info &fi);
+ void format_track_continue(floppy_info &fi);
+
+ void read_id_start(floppy_info &fi);
+ void read_id_continue(floppy_info &fi);
+
+ void scan_start(floppy_info &fi);
+ void verify_data_start(floppy_info &fi);
+
+ void general_continue(floppy_info &fi);
+ void index_callback(floppy_image_device *floppy, int state);
+ bool sector_matches() const;
+
+ void live_start(floppy_info &fi, int live_state);
+ void live_abort();
+ void checkpoint();
+ void rollback();
+ void live_delay(int state);
+ void live_sync();
+ void live_run(attotime limit = attotime::never);
+ void live_write_raw(UINT16 raw);
+ void live_write_fm(UINT8 fm);
+
+ bool read_one_bit(const attotime &limit);
+ bool write_one_bit(const attotime &limit);
+ bool set_output(UINT8 data);
+ bool get_input(UINT8 *data);
};
extern const device_type I8271;
-#endif /* I8271_H_ */
+#endif
diff --git a/src/lib/formats/atom_dsk.c b/src/lib/formats/atom_dsk.c
new file mode 100644
index 00000000000..6a5294a8fb8
--- /dev/null
+++ b/src/lib/formats/atom_dsk.c
@@ -0,0 +1,31 @@
+#include "atom_dsk.h"
+
+atom_format::atom_format() : wd177x_format(formats)
+{
+}
+
+const char *atom_format::name() const
+{
+ return "atom";
+}
+
+const char *atom_format::description() const
+{
+ return "Acorn Atom disk image";
+}
+
+const char *atom_format::extensions() const
+{
+ return "40t,dsk";
+}
+
+const atom_format::format atom_format::formats[] =
+{
+ { // 100k 40 track single sided single density
+ floppy_image::FF_525, floppy_image::SSSD, floppy_image::FM,
+ 4000, 10, 40, 1, 256, {}, 0, {}, 40, 10, 10
+ },
+ {}
+};
+
+const floppy_format_type FLOPPY_ATOM_FORMAT = &floppy_image_format_creator<atom_format>;
diff --git a/src/lib/formats/atom_dsk.h b/src/lib/formats/atom_dsk.h
new file mode 100644
index 00000000000..45187205f1c
--- /dev/null
+++ b/src/lib/formats/atom_dsk.h
@@ -0,0 +1,22 @@
+#ifndef __ATOM_DSK_H__
+#define __ATOM_DSK_H__
+
+#include "flopimg.h"
+#include "wd177x_dsk.h"
+
+class atom_format : public wd177x_format
+{
+public:
+ atom_format();
+
+ virtual const char *name() const;
+ virtual const char *description() const;
+ virtual const char *extensions() const;
+
+private:
+ static const format formats[];
+};
+
+extern const floppy_format_type FLOPPY_ATOM_FORMAT;
+
+#endif
diff --git a/src/mess/drivers/atom.c b/src/mess/drivers/atom.c
index 88d142d15c4..9403c7c62e5 100644
--- a/src/mess/drivers/atom.c
+++ b/src/mess/drivers/atom.c
@@ -247,7 +247,7 @@ READ8_MEMBER( atomeb_state::dos_r )
static ADDRESS_MAP_START( atom_mem, AS_PROGRAM, 8, atom_state )
AM_RANGE(0x0000, 0x09ff) AM_RAM
- AM_RANGE(0x0a00, 0x0a03) AM_MIRROR(0x1f8) AM_DEVREADWRITE(I8271_TAG, i8271_device, read, write)
+ AM_RANGE(0x0a00, 0x0a03) AM_MIRROR(0x1f8) AM_DEVICE(I8271_TAG, i8271_device, map)
AM_RANGE(0x0a04, 0x0a04) AM_MIRROR(0x1f8) AM_DEVREADWRITE(I8271_TAG, i8271_device, data_r, data_w)
AM_RANGE(0x0a05, 0x7fff) AM_RAM
AM_RANGE(0x8000, 0x97ff) AM_RAM AM_SHARE("video_ram")
@@ -583,30 +583,11 @@ WRITE_LINE_MEMBER( atom_state::atom_8271_interrupt_callback )
m_previous_i8271_int_state = state;
}
-/*-------------------------------------------------
- LEGACY_FLOPPY_OPTIONS( atom )
--------------------------------------------------*/
-
-static LEGACY_FLOPPY_OPTIONS_START( atom )
- LEGACY_FLOPPY_OPTION(atom, "dsk,40t", "Atom disk image", basicdsk_identify_default, basicdsk_construct_default, NULL,
- HEADS([1])
- TRACKS([40])
- SECTORS([10])
- SECTOR_LENGTH([256])
- FIRST_SECTOR_ID([0]))
-LEGACY_FLOPPY_OPTIONS_END
-
-/*-------------------------------------------------
- floppy_interface atom_floppy_interface
--------------------------------------------------*/
-
-static const floppy_interface atom_floppy_interface =
+WRITE_LINE_MEMBER( atom_state::motor_w )
{
- FLOPPY_STANDARD_5_25_SSDD_40,
- LEGACY_FLOPPY_OPTIONS_NAME(atom),
- "floppy_5_25"
-};
-
+ m_fdc->subdevice<floppy_connector>("0")->get_device()->mon_w(!state);
+ m_fdc->subdevice<floppy_connector>("1")->get_device()->mon_w(!state);
+}
TIMER_DEVICE_CALLBACK_MEMBER(atom_state::cassette_output_tick)
{
@@ -687,6 +668,13 @@ int atom_state::load_cart(device_image_interface &image, generic_slot_device *sl
return IMAGE_INIT_PASS;
}
+static SLOT_INTERFACE_START(atom_floppies)
+ SLOT_INTERFACE("525sssd", FLOPPY_525_SSSD)
+SLOT_INTERFACE_END
+
+FLOPPY_FORMATS_MEMBER(atom_state::floppy_formats)
+ FLOPPY_ATOM_FORMAT
+FLOPPY_FORMATS_END
/*-------------------------------------------------
MACHINE_DRIVER( atom )
@@ -722,10 +710,11 @@ static MACHINE_CONFIG_START( atom, atom_state )
MCFG_I8255_IN_PORTC_CB(READ8(atom_state, ppi_pc_r))
MCFG_I8255_OUT_PORTC_CB(WRITE8(atom_state, ppi_pc_w))
- MCFG_DEVICE_ADD(I8271_TAG, I8271, 0)
+ MCFG_DEVICE_ADD(I8271_TAG, I8271 , 0)
MCFG_I8271_IRQ_CALLBACK(WRITELINE(atom_state, atom_8271_interrupt_callback))
- MCFG_I8271_FLOPPIES(FLOPPY_0, FLOPPY_1)
- MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(atom_floppy_interface)
+ MCFG_I8271_HDL_CALLBACK(WRITELINE(atom_state, motor_w))
+ MCFG_FLOPPY_DRIVE_ADD(I8271_TAG ":0", atom_floppies, "525sssd", atom_state::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD(I8271_TAG ":1", atom_floppies, "525sssd", atom_state::floppy_formats)
MCFG_CENTRONICS_ADD(CENTRONICS_TAG, centronics_devices, "printer")
MCFG_CENTRONICS_ACK_HANDLER(DEVWRITELINE(R6522_TAG, via6522_device, write_ca1))
diff --git a/src/mess/drivers/bbc.c b/src/mess/drivers/bbc.c
index 8c6815c3eb7..437e6545cb1 100644
--- a/src/mess/drivers/bbc.c
+++ b/src/mess/drivers/bbc.c
@@ -194,8 +194,8 @@ static ADDRESS_MAP_START( bbcb_mem, AS_PROGRAM, 8, bbc_state )
AM_RANGE(0x8000, 0xbfff) AM_READ_BANK("bank4") AM_WRITE(bbc_memoryb4_w) /* 8000-bfff Paged ROM */
AM_RANGE(0xfe30, 0xfe3f) AM_READWRITE(bbc_fe_r, bbc_page_selectb_w) /* R: fe30-fe3f NC Not Connected */
/* W: fe30-fe3f 84LS161 Paged ROM selector */
- AM_RANGE(0xfe80, 0xfe83) AM_DEVREADWRITE("i8271", i8271_device, read, write) /* fe80-fe9f 8271 FDC Floppy disc controller */
- AM_RANGE(0xfe84, 0xfe9f) AM_DEVREADWRITE("i8271", i8271_device, dack_r, dack_w) /* fe80-fe9f 8271 FDC Floppy disc controller */
+ AM_RANGE(0xfe80, 0xfe83) AM_DEVICE("i8271" , i8271_device, map) /* fe80-fe9f 8271 FDC Floppy disc controller */
+ AM_RANGE(0xfe84, 0xfe9f) AM_DEVREADWRITE("i8271", i8271_device, data_r, data_w) /* fe80-fe9f 8271 FDC Floppy disc controller */
AM_IMPORT_FROM(bbc_base)
ADDRESS_MAP_END
@@ -635,13 +635,6 @@ WRITE_LINE_MEMBER(bbc_state::bbcb_acia6850_irq_w)
}
-static const floppy_interface bbc_floppy_interface =
-{
- FLOPPY_STANDARD_5_25_DSDD,
- LEGACY_FLOPPY_OPTIONS_NAME(bbc),
- "floppy_5_25"
-};
-
FLOPPY_FORMATS_MEMBER( bbc_state::floppy_formats_525sd )
FLOPPY_BBC_SSD_525_FORMAT,
FLOPPY_BBC_DSD_525_FORMAT
@@ -824,11 +817,11 @@ static MACHINE_CONFIG_DERIVED( bbcb, bbca )
MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics")
/* fdc */
- MCFG_DEVICE_ADD("i8271", I8271, 0)
+ MCFG_DEVICE_ADD("i8271" , I8271 , 0)
MCFG_I8271_IRQ_CALLBACK(WRITELINE(bbc_state, bbc_i8271_interrupt))
- MCFG_I8271_FLOPPIES(FLOPPY_0, FLOPPY_1)
-
- MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(bbc_floppy_interface)
+ MCFG_I8271_HDL_CALLBACK(WRITELINE(bbc_state, motor_w))
+ MCFG_FLOPPY_DRIVE_ADD("i8271:0", bbc_floppies_525, "qd", bbc_state::floppy_formats_525sd)
+ MCFG_FLOPPY_DRIVE_ADD("i8271:1", bbc_floppies_525, "qd", bbc_state::floppy_formats_525sd)
/* software lists */
MCFG_DEVICE_REMOVE("cass_ls_a")
@@ -844,8 +837,6 @@ static MACHINE_CONFIG_DERIVED(bbcb1770, bbcb)
/* fdc */
MCFG_DEVICE_REMOVE("i8271")
- MCFG_DEVICE_REMOVE(FLOPPY_0)
- MCFG_DEVICE_REMOVE(FLOPPY_1)
MCFG_WD1770_ADD("wd1770", XTAL_16MHz / 2)
MCFG_WD_FDC_INTRQ_CALLBACK(WRITELINE(bbc_state, bbc_wd177x_intrq_w))
diff --git a/src/mess/drivers/imds2.c b/src/mess/drivers/imds2.c
index 4db7ffd7555..aae8a4506f7 100644
--- a/src/mess/drivers/imds2.c
+++ b/src/mess/drivers/imds2.c
@@ -140,7 +140,7 @@ static ADDRESS_MAP_START(ioc_io_map , AS_IO , 8 , imds2_state)
AM_RANGE(0x90 , 0x9f) AM_READ(imds2_kb_read)
AM_RANGE(0xa0 , 0xaf) AM_READ(imds2_ioc_status_r)
AM_RANGE(0xb0 , 0xbf) AM_READ(imds2_ioc_dbbin_r)
- AM_RANGE(0xc0 , 0xcf) AM_DEVREADWRITE("iocfdc" , i8271_device , read , write)
+ AM_RANGE(0xc0 , 0xcf) AM_DEVICE("iocfdc" , i8271_device, map)
AM_RANGE(0xd0 , 0xdf) AM_DEVREADWRITE("ioccrtc" , i8275_device , read , write)
AM_RANGE(0xe0 , 0xef) AM_DEVREADWRITE("ioctimer" , pit8253_device , read , write);
// DMA controller range doesn't extend to 0xff because register 0xfd needs to be read as 0xff
@@ -171,11 +171,12 @@ imds2_state::imds2_state(const machine_config &mconfig, device_type type, const
m_iocbeep(*this , "iocbeep"),
m_ioctimer(*this , "ioctimer"),
m_iocfdc(*this , "iocfdc"),
+ m_flop0(*this, "iocfdc:0"),
+ m_flop1(*this, "iocfdc:1"),
m_iocpio(*this , "iocpio"),
m_kbcpu(*this , "kbcpu"),
m_palette(*this , "palette"),
m_gfxdecode(*this, "gfxdecode"),
- m_floppy0(*this , FLOPPY_0),
m_centronics(*this , "centronics"),
m_io_key0(*this , "KEY0"),
m_io_key1(*this , "KEY1"),
@@ -551,6 +552,17 @@ I8275_DRAW_CHARACTER_MEMBER(imds2_state::crtc_display_pixels)
}
}
+int imds2_state::floppy_load(floppy_image_device *dev)
+{
+ dev->mon_w(0);
+ return IMAGE_INIT_PASS;
+}
+
+void imds2_state::floppy_unload(floppy_image_device *dev)
+{
+ dev->mon_w(1);
+}
+
void imds2_state::driver_start()
{
// Allocate 64k for IPC RAM
@@ -566,8 +578,11 @@ void imds2_state::driver_start()
void imds2_state::machine_start()
{
- m_floppy0->floppy_mon_w(0);
- m_floppy0->floppy_drive_set_ready_state(1 , 0);
+ // As far as I can tell from the schmatic, there's no software motor control
+ m_flop0->get_device()->setup_load_cb(floppy_image_device::load_cb(FUNC(imds2_state::floppy_load), this));
+ m_flop0->get_device()->setup_unload_cb(floppy_image_device::unload_cb(FUNC(imds2_state::floppy_unload), this));
+ m_flop1->get_device()->setup_load_cb(floppy_image_device::load_cb(FUNC(imds2_state::floppy_load), this));
+ m_flop1->get_device()->setup_unload_cb(floppy_image_device::unload_cb(FUNC(imds2_state::floppy_unload), this));
}
void imds2_state::video_start()
@@ -580,6 +595,10 @@ void imds2_state::machine_reset()
m_iocbeep->set_frequency(IOC_BEEP_FREQ);
m_ipc_control = 0x00;
m_ipc_ioc_status = 0x0f;
+ m_flop0->get_device()->mon_w(!m_flop0->get_device()->exists());
+ m_flop1->get_device()->mon_w(!m_flop1->get_device()->exists());
+
+ m_iocfdc->set_rate(500000); // The IMD images show a rate of 500kbps
}
bool imds2_state::imds2_in_ipc_rom(offs_t offset) const
@@ -737,15 +756,9 @@ static GFXDECODE_START(imds2)
GFXDECODE_ENTRY("gfx1" , 0x0000 , imds2_charlayout , 0 , 1)
GFXDECODE_END
-static LEGACY_FLOPPY_OPTIONS_START(imds2)
-LEGACY_FLOPPY_OPTIONS_END
-
-static const floppy_interface imds2_floppy_interface =
-{
- FLOPPY_STANDARD_8_SSSD,
- LEGACY_FLOPPY_OPTIONS_NAME(imds2),
- "floppy_8"
-};
+static SLOT_INTERFACE_START( imds2_floppies )
+ SLOT_INTERFACE( "8sssd", FLOPPY_8_SSSD )
+SLOT_INTERFACE_END
static MACHINE_CONFIG_START(imds2 , imds2_state)
MCFG_CPU_ADD("ipccpu" , I8085A , IPC_XTAL_Y2 / 2) // 4 MHz
@@ -805,8 +818,8 @@ static MACHINE_CONFIG_START(imds2 , imds2_state)
MCFG_I8257_OUT_HRQ_CB(WRITELINE(imds2_state, imds2_hrq_w))
MCFG_I8257_IN_MEMR_CB(READ8(imds2_state , imds2_ioc_mem_r))
MCFG_I8257_OUT_MEMW_CB(WRITE8(imds2_state , imds2_ioc_mem_w))
- MCFG_I8257_IN_IOR_1_CB(DEVREAD8("iocfdc" , i8271_device , dack_r))
- MCFG_I8257_OUT_IOW_1_CB(DEVWRITE8("iocfdc" , i8271_device , dack_w))
+ MCFG_I8257_IN_IOR_1_CB(DEVREAD8("iocfdc" , i8271_device , data_r))
+ MCFG_I8257_OUT_IOW_1_CB(DEVWRITE8("iocfdc" , i8271_device , data_w))
MCFG_I8257_OUT_IOW_2_CB(DEVWRITE8("ioccrtc" , i8275_device , dack_w))
MCFG_DEVICE_ADD("ioctimer" , PIT8253 , 0)
@@ -816,9 +829,8 @@ static MACHINE_CONFIG_START(imds2 , imds2_state)
MCFG_DEVICE_ADD("iocfdc" , I8271 , IOC_XTAL_Y1 / 2)
MCFG_I8271_DRQ_CALLBACK(DEVWRITELINE("iocdma" , i8257_device , dreq1_w))
- MCFG_I8271_FLOPPIES(FLOPPY_0 , FLOPPY_1)
-
- MCFG_LEGACY_FLOPPY_DRIVE_ADD(FLOPPY_0, imds2_floppy_interface)
+ MCFG_FLOPPY_DRIVE_ADD("iocfdc:0", imds2_floppies, "8sssd", floppy_image_device::default_floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("iocfdc:1", imds2_floppies, "8sssd", floppy_image_device::default_floppy_formats)
MCFG_CPU_ADD("iocpio" , I8041 , IOC_XTAL_Y3)
MCFG_CPU_IO_MAP(pio_io_map)
diff --git a/src/mess/includes/atom.h b/src/mess/includes/atom.h
index 62992b67469..bd7b2427897 100644
--- a/src/mess/includes/atom.h
+++ b/src/mess/includes/atom.h
@@ -13,7 +13,7 @@
#include "machine/ram.h"
#include "imagedev/snapquik.h"
#include "formats/atom_tap.h"
-#include "formats/basicdsk.h"
+#include "formats/atom_dsk.h"
#include "formats/uef_cas.h"
#include "bus/centronics/ctronics.h"
#include "machine/6522via.h"
@@ -46,6 +46,7 @@ public:
m_maincpu(*this, SY6502_TAG),
m_vdg(*this, MC6847_TAG),
m_cassette(*this, "cassette"),
+ m_fdc(*this, I8271_TAG),
m_centronics(*this, CENTRONICS_TAG),
m_speaker(*this, "speaker"),
m_cart(*this, "cartslot"),
@@ -67,6 +68,7 @@ public:
required_device<cpu_device> m_maincpu;
required_device<mc6847_base_device> m_vdg;
required_device<cassette_image_device> m_cassette;
+ optional_device<i8271_device> m_fdc;
required_device<centronics_device> m_centronics;
required_device<speaker_sound_device> m_speaker;
optional_device<generic_slot_device> m_cart;
@@ -95,6 +97,7 @@ public:
DECLARE_READ8_MEMBER( vdg_videoram_r );
DECLARE_INPUT_CHANGED_MEMBER( trigger_reset );
DECLARE_WRITE_LINE_MEMBER( atom_8271_interrupt_callback );
+ DECLARE_WRITE_LINE_MEMBER( motor_w );
/* video state */
required_shared_ptr<UINT8> m_video_ram;
@@ -109,6 +112,7 @@ public:
/* devices */
int m_previous_i8271_int_state;
+ DECLARE_FLOPPY_FORMATS(floppy_formats);
TIMER_DEVICE_CALLBACK_MEMBER(cassette_output_tick);
int load_cart(device_image_interface &image, generic_slot_device *slot);
diff --git a/src/mess/includes/bbc.h b/src/mess/includes/bbc.h
index 9f5dcb19327..5b8e56d25e5 100644
--- a/src/mess/includes/bbc.h
+++ b/src/mess/includes/bbc.h
@@ -167,6 +167,7 @@ public:
DECLARE_WRITE_LINE_MEMBER(write_cts_serial);
DECLARE_INPUT_CHANGED_MEMBER( trigger_reset );
DECLARE_WRITE_LINE_MEMBER(bbc_i8271_interrupt);
+ DECLARE_WRITE_LINE_MEMBER(motor_w);
UPD7002_GET_ANALOGUE(BBC_get_analogue_input);
UPD7002_EOC(BBC_uPD7002_EOC);
diff --git a/src/mess/includes/imds2.h b/src/mess/includes/imds2.h
index 2b7b20de074..298b808be82 100644
--- a/src/mess/includes/imds2.h
+++ b/src/mess/includes/imds2.h
@@ -79,11 +79,12 @@ class imds2_state : public driver_device
required_device<beep_device> m_iocbeep;
required_device<pit8253_device> m_ioctimer;
required_device<i8271_device> m_iocfdc;
+ required_device<floppy_connector> m_flop0;
+ required_device<floppy_connector> m_flop1;
required_device<i8041_device> m_iocpio;
required_device<i8741_device> m_kbcpu;
required_device<palette_device> m_palette;
required_device<gfxdecode_device> m_gfxdecode;
- required_device<legacy_floppy_image_device> m_floppy0;
required_device<centronics_device> m_centronics;
required_ioport m_io_key0;
required_ioport m_io_key1;
@@ -101,6 +102,8 @@ class imds2_state : public driver_device
void imds2_update_beeper(void);
void imds2_update_printer(void);
+ int floppy_load(floppy_image_device *dev);
+ void floppy_unload(floppy_image_device *dev);
// IPC control port
UINT8 m_ipc_control;
diff --git a/src/mess/machine/bbc.c b/src/mess/machine/bbc.c
index 88ced246f43..3ffefc8a585 100644
--- a/src/mess/machine/bbc.c
+++ b/src/mess/machine/bbc.c
@@ -1439,6 +1439,12 @@ WRITE_LINE_MEMBER(bbc_state::bbc_i8271_interrupt)
m_previous_i8271_int_state = state;
}
+WRITE_LINE_MEMBER(bbc_state::motor_w)
+{
+ m_i8271->subdevice<floppy_connector>("0")->get_device()->mon_w(!state);
+ m_i8271->subdevice<floppy_connector>("1")->get_device()->mon_w(!state);
+}
+
/**************************************
WD1770 disc control function