// license:BSD-3-Clause // copyright-holders:Carl,Olivier Galibert #ifndef I8271N_H_ #define I8271N_H_ #include "imagedev/floppy.h" #include "fdc_pll.h" #define MCFG_I8271_IRQ_CALLBACK(_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_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 ***************************************************************************/ class i8271_device : public device_t { public: i8271_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); ~i8271_device() {} template static devcb_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast(device).intrq_cb.set_callback(object); } template static devcb_base &set_drq_wr_callback(device_t &device, _Object object) { return downcast(device).drq_cb.set_callback(object); } template static devcb_base &set_hdl_wr_callback(device_t &device, _Object object) { return downcast(device).hdl_cb.set_callback(object); } template static devcb_base &set_opt_wr_callback(device_t &device, _Object object) { return downcast(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); 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(); 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 }; 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); }; extern const device_type I8271; #endif