/* Interface */ #ifndef __SMC92X4_H__ #define __SMC92X4_H__ #include "ti99_hd.h" #include "imagedev/flopdrv.h" #include "formats/imageutl.h" #include "imagedev/harddriv.h" #include "harddisk.h" #define INPUT_STATUS 0x00 #define OUTPUT_DMA_ADDR 0x01 #define OUTPUT_OUTPUT1 0x02 #define OUTPUT_OUTPUT2 0x03 #define MFMHD_TRACK00 0x80 #define MFMHD_SEEKCOMP 0x40 #define MFMHD_WRFAULT 0x20 #define MFMHD_READY 0x10 #define MFMHD_INDEX 0x08 #define BAD_SECTOR 0x1000 #define BAD_CRC 0x2000 extern const device_type SMC92X4; /* Definition of bits in the Disk-Status register */ #define DS_ECCERR 0x80 /* ECC error */ #define DS_INDEX 0x40 /* index point */ #define DS_SKCOM 0x20 /* seek complete */ #define DS_TRK00 0x10 /* track 0 */ #define DS_UDEF 0x08 /* user-defined */ #define DS_WRPROT 0x04 /* write protect */ #define DS_READY 0x02 /* drive ready bit */ #define DS_WRFAULT 0x01 /* write fault */ // Interrupt line. To be connected with the controller PCB. #define MCFG_SMC92X4_INTRQ_CALLBACK(_write) \ devcb = &smc92x4_device::set_intrq_wr_callback(*device, DEVCB2_##_write); // DMA in progress line. To be connected with the controller PCB. #define MCFG_SMC92X4_DIP_CALLBACK(_write) \ devcb = &smc92x4_device::set_dip_wr_callback(*device, DEVCB2_##_write); // Auxiliary Bus. These 8 lines need to be connected to external latches // and to a counter circuitry which works together with the external RAM. // We use the S0/S1 lines as address lines. #define MCFG_SMC92X4_AUXBUS_OUT_CALLBACK(_write) \ devcb = &smc92x4_device::set_auxbus_wr_callback(*device, DEVCB2_##_write); // Auxiliary Bus. This is only used for S0=S1=0. #define MCFG_SMC92X4_AUXBUS_IN_CALLBACK(_read) \ devcb = &smc92x4_device::set_auxbus_rd_callback(*device, DEVCB2_##_read); // Callback to read the contents of the external RAM via the data bus. // Note that the address must be set and automatically increased // by external circuitry. #define MCFG_SMC92X4_DMA_IN_CALLBACK(_read) \ devcb = &smc92x4_device::set_dma_rd_callback(*device, DEVCB2_##_read); // Callback to write the contents of the external RAM via the data bus. // Note that the address must be set and automatically increased // by external circuitry. */ #define MCFG_SMC92X4_DMA_OUT_CALLBACK(_write) \ devcb = &smc92x4_device::set_dma_wr_callback(*device, DEVCB2_##_write); struct smc92x4_interface { // Disk format support. This flag allows to choose between the full // FM/MFM format and an abbreviated track layout. The difference results // from legal variations of the layout. This is not part of // the smc92x4 specification, but it allows to keep the image format // simple without too much case checking. Should be removed as soon as // the respective disk formats support the full format. int full_track_layout; }; class smc92x4_device : public device_t { public: smc92x4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); template static devcb2_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_intrq.set_callback(object); } template static devcb2_base &set_dip_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_dip.set_callback(object); } template static devcb2_base &set_auxbus_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_auxbus.set_callback(object); } template static devcb2_base &set_auxbus_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_auxbus.set_callback(object); } template static devcb2_base &set_dma_rd_callback(device_t &device, _Object object) { return downcast(device).m_in_dma.set_callback(object); } template static devcb2_base &set_dma_wr_callback(device_t &device, _Object object) { return downcast(device).m_out_dma.set_callback(object); } DECLARE_READ8_MEMBER( read ); DECLARE_WRITE8_MEMBER( write ); // Used to turn off the delays. void set_timing(bool realistic); // Used to reconfigure the drive connections. Drive selection is done // using the select lines and maybe also the user-programmable outputs. void connect_floppy_drive(legacy_floppy_image_device *drive); void connect_hard_drive(mfm_harddisk_device *drive); void reset(); protected: virtual void device_start(void); virtual void device_reset(void); private: devcb2_write_line m_out_intrq; // INT line devcb2_write_line m_out_dip; // DMA in progress line devcb2_write8 m_out_auxbus; // AB0-7 lines (using S0,S1 as address) devcb2_read8 m_in_auxbus; // AB0-7 lines (S0=S1=0) devcb2_read8 m_in_dma; // DMA read access to the cache buffer devcb2_write8 m_out_dma; // DMA write access to the cache buffer UINT8 m_output1; // internal register "output1" UINT8 m_output2; // internal register "output2" void set_dip(line_state value); int image_is_single_density(); bool in_single_density_mode(); void copyid(chrn_id id1, chrn_id_hd *id2); void set_interrupt(); void clear_interrupt(); void set_command_done(int flags); void set_command_done(); void set_dma_address(int pos2316, int pos1508, int pos0700); void dma_add_offset(int offset); void sync_status_in(); void sync_latches_out(); void timed_sector_read_request(); void timed_sector_write_request(); void timed_track_request(); void timed_seek_request(); virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); UINT8 cylinder_to_ident(int cylinder); int ident_to_cylinder(UINT8 ident); void update_id_regs(chrn_id_hd id); void read_id_field(int *steps, int *direction, chrn_id_hd *id); int verify(chrn_id_hd *id, bool check_sector); void data_transfer_read(chrn_id_hd id, int transfer_enable); void data_transfer_write(chrn_id_hd id, int deldata, int redcur, int precomp, bool write_long); void read_write_sectors(); void read_sectors_continue(); void write_sectors_continue(); void restore_drive(); void restore_continue(); void step_in_out(); void step_continue(); void poll_drives(); void drive_select(int driveparm); void seek_read_id(); void seek_read_id_continue(); void format_track(); void format_track_continue(); void format_floppy_track(int flags); void format_harddisk_track(int flags); void read_track(); void read_track_continue(); void read_floppy_track(bool transfer_only_ids); void read_harddisk_track(bool transfer_only_ids); void process_after_callback(); void process_command(UINT8 opcode); int m_selected_drive_type; // We need to store the types, although this is not the case in the // real hardware. The reason is that poll_drives wants to select the // drives without knowing their kinds. In reality this does not matter, // since we only check for the seek_complete line, but in our case, // floppy and harddrive are pretty different, and we need to know which // one to check. int m_types[4]; int m_head_load_delay_enable; int m_register_pointer; UINT8 m_register_r[12]; UINT8 m_register_w[12]; /* timers to delay execution/completion of commands */ emu_timer *m_timer_data, *m_timer_rs, *m_timer_ws, *m_timer_seek, *m_timer_track; /* Flag which determines whether to use realistic timing. */ bool m_use_real_timing; /* Required to store the current iteration within restore. */ int m_seek_count; /* Recent command. */ UINT8 m_command; /* Stores the step direction. */ int m_step_direction; /* Stores the buffered flag. */ bool m_buffered; /* Stores the recent id field. */ chrn_id_hd m_recent_id; /* Indicates whether an ID has been found. */ bool m_found_id; /* Indicates whether we are already past the seek_id phase in read/write sector. */ bool m_after_seek; /* Determines whether the command will be continued. */ bool m_to_be_continued; bool m_full_track_layout; // Link to attached drive (hard / floppy disk) // Hard disks must be instances of mfmhd_device; floppy disks are the common drives. // We expect the embedding board to replace the drive according to the // select lines. legacy_floppy_image_device *m_drive; mfm_harddisk_device *m_harddisk; }; #define MCFG_SMC92X4_ADD(_tag, _intrf) \ MCFG_DEVICE_ADD(_tag, SMC92X4, 0) \ MCFG_DEVICE_CONFIG(_intrf) #endif