// license:BSD-3-Clause
// copyright-holders:Carl,Olivier Galibert
#ifndef MAME_MACHINE_I8271_H
#define MAME_MACHINE_I8271_H
#pragma once
#include "fdc_pll.h"
class floppy_image_device;
/***************************************************************************
MACROS
***************************************************************************/
class i8271_device : public device_t
{
public:
i8271_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto intrq_wr_callback() { return intrq_cb.bind(); }
auto drq_wr_callback() { return drq_cb.bind(); }
auto hdl_wr_callback() { return hdl_cb.bind(); }
auto opt_wr_callback() { return opt_cb.bind(); }
uint8_t read(offs_t offset);
void write(offs_t offset, uint8_t data);
uint8_t data_r();
void data_w(uint8_t data);
void ready_w(bool val);
void set_rate(int rate); // rate in bps, to be used when the fdc is externally frequency-controlled
void set_ready_line_connected(bool ready);
void set_select_lines_connected(bool select);
void set_floppy(floppy_image_device *image);
void soft_reset();
void map(address_map &map);
protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
private:
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_t pcn, badtrack[2];
bool live, index, ready;
};
struct live_info {
enum { PT_NONE, PT_CRC_1, PT_CRC_2 };
attotime tm;
int state, next_state;
floppy_info *fi;
uint16_t shift_reg;
uint16_t crc;
int bit_counter, byte_counter, previous_type;
bool data_separator_phase, data_bit_context;
uint8_t data_reg;
uint8_t 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_t command[6], dma_data, oport;
uint8_t rr, scan_sec, moder;
uint8_t precomp, perpmode, scan_cnt[2];
uint8_t srate, hset, icnt, hload;
int sector_size;
int cur_rate;
int idle_icnt;
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
};
uint8_t sr_r();
uint8_t rr_r();
void reset_w(uint8_t data) { if(data == 1) soft_reset(); }
void cmd_w(uint8_t data);
void param_w(uint8_t data);
void delay_cycles(emu_timer *tm, int cycles);
void set_drq(bool state);
void set_irq(bool state);
bool get_ready(int fid);
int calc_sector_size(uint8_t 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_t raw);
void live_write_fm(uint8_t fm);
bool read_one_bit(const attotime &limit);
bool write_one_bit(const attotime &limit);
bool set_output(uint8_t data);
bool get_input(uint8_t *data);
};
DECLARE_DEVICE_TYPE(I8271, i8271_device)
#endif // MAME_MACHINE_I8271_H