summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/machine/smc92x4.h
blob: 4b06c14dd1d5e9dcc7cc0e6def06d408f98ab9a7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/* 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<class _Object> static devcb2_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast<smc92x4_device &>(device).m_out_intrq.set_callback(object); }
	template<class _Object> static devcb2_base &set_dip_wr_callback(device_t &device, _Object object) { return downcast<smc92x4_device &>(device).m_out_dip.set_callback(object); }
	template<class _Object> static devcb2_base &set_auxbus_wr_callback(device_t &device, _Object object) { return downcast<smc92x4_device &>(device).m_out_auxbus.set_callback(object); }
	template<class _Object> static devcb2_base &set_auxbus_rd_callback(device_t &device, _Object object) { return downcast<smc92x4_device &>(device).m_in_auxbus.set_callback(object); }
	template<class _Object> static devcb2_base &set_dma_rd_callback(device_t &device, _Object object) { return downcast<smc92x4_device &>(device).m_in_dma.set_callback(object); }
	template<class _Object> static devcb2_base &set_dma_wr_callback(device_t &device, _Object object) { return downcast<smc92x4_device &>(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