1 // license:BSD-3-Clause
2 // copyright-holders:Juergen Buchmueller
3 /**********************************************************
4  *   DIABLO31 and DIABLO44 hard drive support
5  **********************************************************/
6 #include "emu.h"
7 #include "diablo_hd.h"
8 
9 /**
10  *
11  * Just for completeness' sake:
12  * The mapping of disk controller connector P2 pins to the
13  * Winchester disk drive signals (see drive.h)
14  * <PRE>
15  * Alto Controller     Winchester
16  * P2 signal           disk bus
17  * -----------------------------------------------
18  *  1 GND              D_GROUND
19  *  2 RDCLK'           A_READ_CLOCK
20  *  3 WRDATA'          B_WRITE_DATA_AND_CLOCK
21  *  4 SRWRDY'          F_S_R_W
22  *  5 DISK             L_SELECT_LINE_UNIT_1
23  *  6 CYL(7)'          N_CYL_7
24  *  7 DISK'            R_SELECT_LINE_UNIT_2
25  *  8 CYL(2)'          T_CYL_2
26  *  9 ???              V_SELECT_LINE_UNIT_3
27  * 10 CYL(4)'          X_CYL_4
28  * 11 CYL(0)'          Z_CYL_0
29  * 12 CYL(1)'          BB_CYL_1
30  * 13 CYL(3)'          FF_CYL_3
31  * 14 ???              KK_BIT_2
32  * 15 CYL(8)'          LL_CYL_8
33  * 16 ADRACK'          NN_ADDX_ACKNOWLEDGE
34  * 17 SKINC'           TT_SEEK_INCOMPLETE
35  * 18 LAI'             XX_LOG_ADDX_INTERLOCK
36  * 19 CYL(6)'          RR_CYL_6
37  * 20 RESTOR'          VV_RESTORE
38  * 21 ???              UU_BIT_16
39  * 22 STROBE'          SS_STROBE
40  * 23 ???              MM_BIT_8
41  * 24 ???              KK_BIT_4
42  * 25 ???              HH_WRITE_CHK
43  * 26 WRTGATE'         EE_WRITE_GATE
44  * 27 ???              CC_BIT_SECTOR_ADDX
45  * 28 HEAD'            AA_HEAD_SELECT
46  * 29 ???              Y_INDEX_MARK
47  * 30 SECT(4)'         W_SECTOR_MARK
48  * 31 READY'           U_FILE_READY
49  * 32 ???              S_PSEUDO_SECTOR_MARK
50  * 33 ???              P_WRITE_PROTECT_IND
51  * 34 ???              H_WRITE_PROTECT_INPUT_ATTENTION
52  * 35 ERGATE'          K_ERASE_GATE
53  * 36 ???              M_HIGH_DENSITY
54  * 37 CYL(5)'          J_CYL_5
55  * 38 RDDATA'          C_READ_DATA
56  * 39 RDGATE'          E_READ_GATE
57  * 40 GND              ??
58  * </PRE>
59  */
60 
61 #ifndef DIABLO_DEBUG
62 #define DIABLO_DEBUG    1                           //!< set to 1 to enable debug log output
63 #endif
64 
65 #define LOG_DRIVE(...) do { if (DIABLO_DEBUG) logprintf(__VA_ARGS__); } while (0)
66 
67 
diablo_hd_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)68 diablo_hd_device::diablo_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
69 	device_t(mconfig, DIABLO_HD, tag, owner, clock),
70 	m_log_level(8),
71 	m_diablo31(true),
72 	m_unit(0),
73 	m_packs(1),
74 	m_rotation_time(),
75 	m_sector_time(),
76 	m_sector_mark_0_time(),
77 	m_sector_mark_1_time(),
78 	m_bit_time(),
79 	m_s_r_w_0(1),
80 	m_ready_0(1),
81 	m_sector_mark_0(1),
82 	m_addx_acknowledge_0(1),
83 	m_log_addx_interlock_0(1),
84 	m_seek_incomplete_0(1),
85 	m_egate_0(1),
86 	m_wrgate_0(1),
87 	m_rdgate_0(1),
88 	m_cylinders(DIABLO_CYLINDERS),
89 	m_pages(DIABLO_PAGES),
90 	m_seekto(0),
91 	m_restore(0),
92 	m_cylinder(-1),
93 	m_head(-1),
94 	m_sector(-1),
95 	m_page(-1),
96 	m_bits(),
97 	m_rdfirst(-1),
98 	m_rdlast(-1),
99 	m_wrfirst(-1),
100 	m_wrlast(-1),
101 	m_sector_callback_cookie(nullptr),
102 	m_sector_callback(nullptr),
103 	m_timer(nullptr),
104 	m_image(nullptr),
105 	m_handle(nullptr),
106 	m_disk(nullptr)
107 {
108 	memset(m_description, 0x00, sizeof(m_description));
109 }
110 
111 /**
112  * @brief diablo_hd_device destructor
113  * Free all m_cache and m_bits pages and the arrays
114  */
~diablo_hd_device()115 diablo_hd_device::~diablo_hd_device()
116 {
117 }
118 
119 template <typename Format, typename... Params>
logprintf(int level,Format && fmt,Params &&...args)120 void diablo_hd_device::logprintf(int level, Format &&fmt, Params &&... args)
121 {
122 	if (level <= m_log_level)
123 		logerror(std::forward<Format>(fmt), std::forward<Params>(args)...);
124 }
125 
set_sector_callback(void * cookie,void (* callback)(void *,int))126 void diablo_hd_device::set_sector_callback(void *cookie, void (*callback)(void *, int))
127 {
128 	if (m_sector_callback_cookie == cookie && m_sector_callback == callback)
129 		return;
130 	LOG_DRIVE(0,"[DHD%u] cookie=%p callback=%p\n", m_unit, cookie, (void *)callback);
131 	m_sector_callback_cookie = cookie;
132 	m_sector_callback = callback;
133 }
134 
135 #define DIABLO31_ROTATION_TIME attotime::from_usec(39900)       //!< DIABLO 31 rotation time is approx. 40ms
136 #define DIABLO31_SECTOR_TIME attotime::from_usec(39900/12)      //!< DIABLO 31 sector time
137 /**
138  * @brief DIABLO 31 bit clock is 3330kHz ~= 300ns per bit
139  * ~= 133333 bits/track (?)
140  * ~= 11111 bits/sector
141  * ~= 347 words/sector
142  */
143 #define DIABLO31_BIT_TIME(bits) attotime::from_nsec(300*(bits))
144 #define DIABLO31_SECTOR_BITS    10432
145 #define DIABLO31_SECTOR_WORDS   347                             //!< DIABLO 31 possible sector words
146 #define DIABLO31_SECTOR_MARK_PULSE_PRE DIABLO31_BIT_TIME(16)    //!< pulse width of sector mark before the next sector begins
147 #define DIABLO31_SECTOR_MARK_PULSE_POST DIABLO31_BIT_TIME(16)   //!< pulse width of sector mark after the next sector began
148 
149 #define DIABLO44_ROTATION_TIME attotime::from_usec(25000)       //!< DIABLO 44 rotation time is approx. 25ms
150 #define DIABLO44_SECTOR_TIME attotime::from_usec(25000/12)      //!< DIABLO 44 sector time
151 /**
152  * @brief DIABLO 44 bit clock is 5000kHz ~= 200ns per bit
153  * ~= 125184 bits/track (?)
154  * ~= 10432 bits/sector
155  * ~= 325 words/sector
156  */
157 #define DIABLO44_BIT_TIME(bits) attotime::from_nsec(200*(bits))
158 #define DIABLO44_SECTOR_BITS    10432
159 #define DIABLO44_SECTOR_WORDS   325                             //!< DIABLO 44 possible sector words
160 #define DIABLO44_SECTOR_MARK_PULSE_PRE DIABLO44_BIT_TIME(16)    //!< pulse width of sector mark before the next sector begins
161 #define DIABLO44_SECTOR_MARK_PULSE_POST DIABLO44_BIT_TIME(16)   //!< pulse width of sector mark after the next sector began
162 
163 #define MFROBL          34      //!< from the microcode: disk header preamble is 34 words
164 #define MFRRDL          21      //!< from the microcode: disk header read delay is 21 words
165 #define MIRRDL          4       //!< from the microcode: interrecord read delay is 4 words
166 #define MIROBL          3       //!< from the microcode: disk interrecord preamble is 3 words
167 #define MRPAL           3       //!< from the microcode: disk read postamble length is 3 words
168 #define MWPAL           5       //!< from the microcode: disk write postamble length is 5 words
169 
170 #define GUARD_ZONE_BITS (16*32) //!< end of the guard zone at the beginning of a sector (wild guess!)
171 
172 /**
173  * @brief description of the sector layout (reverse engineered)
174  * <PRE>
175  *
176  *                                   xx.x msec sector mark pulses
177  * -+   +-------------------------------------------------------------------------------+   +--
178  *  |   |                                                                               |   |
179  *  +---+                                                                               +---+
180  *
181  *    |                                                                                   |
182  *
183  *    +------+----+------+-----+------+----+-------+-----+------+----+-------+-----+------+
184  *    | PRE- |SYNC|HEADER|CKSUM| PRE- |SYNC| LABEL |CKSUM| PRE- |SYNC| DATA  |CKSUM| POST |
185  *    |AMBLE1|  1 |      |  1  |AMBLE2|  2 |       |  2  |AMBLE3|  3 |       |  3  |AMBLE |
186  *    +------+----+------+-----+------+----+-------+-----+------+----+-------+-----+------+
187  *
188  *    |                                                                                   |
189  *
190  *    +-----------------------------------------------------------------------------------+
191  *    |                                                                                   |
192  * ---+                                                                                   +----
193  *      FORMAT WRITE GATE FOR INITIALIZING
194  *    |                                                                                   |
195  *
196  *    |                                                    +------------------------------+
197  *                                                         |                              |
198  * ---|----------------------------------------------------+                              +----
199  *      WRITE GATE FOR DATA XFER (*)
200  *    |                                                                                   |
201  *
202  *    |                          +-----------------------+-+------------------------------+
203  *                               |                       | | may be continuous (?)        |
204  * ------------------------------+                       +-+                              +----
205  * ???  WRITE GATE FOR LABEL AND DATA XFER (*)
206  *    |                                                                                   |
207  *
208  *    |   +--------------------+   +---------------------+   +----------------------------+
209  *        |                    |   |                     |   |                            |
210  * -------+                    +---+                     +---+                            +----
211  *      READ GATE FOR INITIALIZING OR DATA XFER (**)
212  *
213  *
214  *  (*) Enable should be delayed 1 byte/word time from last bit of checks sum.
215  *  (**) Read Gate should be enabled half way through the preamble area. This
216  *       ensures reading a zero field for data separator synchronization.
217  *
218  * </PRE>
219  */
220 
221 #define DIABLO_PAGENO_WORDS 1       //!< number of words in a page number (this doesn't really belong here)
222 #define DIABLO_HEADER_WORDS 2       //!< number of words in a header (this doesn't really belong here)
223 #define DIABLO_LABEL_WORDS  8       //!< number of words in a label (this doesn't really belong here)
224 #define DIABLO_DATA_WORDS   256     //!< number of data words (this doesn't really belong here)
225 #define DIABLO_CKSUM_WORDS  1       //!< number of words for a checksum (this doesn't really belong here)
226 
227 /**
228  * @brief format of the cooked disk image sectors, i.e. pure data
229  *
230  * The available images are a multiple of 267 words (534 bytes) per sector,
231  * 1 word page number
232  * 2 words header
233  * 8 words label
234  * 256 words data
235  */
236 typedef struct {
237 	uint8_t pageno[2*DIABLO_PAGENO_WORDS];    //!< sector page number
238 	uint8_t header[2*DIABLO_HEADER_WORDS];    //!< sector header words
239 	uint8_t label[2*DIABLO_LABEL_WORDS];      //!< sector label words
240 	uint8_t data[2*DIABLO_DATA_WORDS];        //!< sector data words
241 }   diablo_sector_t;
242 
243 /**
244  * @brief write a bit into an array of uint32_t
245  * @param bits pointer to array of bits
246  * @param dst destination index
247  * @param bit bit value
248  * @return next destination index
249  */
WRBIT(uint32_t * bits,size_t dst,int bit)250 static inline size_t WRBIT(uint32_t* bits, size_t dst, int bit)
251 {
252 	if (bit) {
253 		bits[(dst)/32] |= 1 << ((dst) % 32);
254 	} else {
255 		bits[(dst)/32] &= ~(1 << ((dst) % 32));
256 	}
257 	return ++dst;
258 }
259 
260 /**
261  * @brief read a bit from an array of uint32_t
262  * @param bits pointer to array of bits
263  * @param src source index
264  * @param bit reference to the bit to set
265  * @return next source index
266  */
RDBIT(uint32_t * bits,size_t src,int & bit)267 static inline size_t RDBIT(uint32_t* bits, size_t src, int& bit)
268 {
269 	bit = (bits[src/32] >> (src % 32)) & 1;
270 	return ++src;
271 }
272 
273 /**
274  * @brief calculate the sector from the logical block address and read it
275  *
276  * Modifies drive's page by calculating the logical
277  * block address from cylinder, head, and sector.
278  */
read_sector()279 void diablo_hd_device::read_sector()
280 {
281 	/* If there's no drive, just reset the page number */
282 	if (!m_image) {
283 		LOG_DRIVE(0,"[DHD%u]   CHS:%03d/%d/%02d => no image\n", m_unit, m_cylinder, m_head, m_sector);
284 		m_page = -1;
285 		return;
286 	}
287 	if (m_cylinder < 0 || m_cylinder >= m_cylinders) {
288 		LOG_DRIVE(0,"[DHD%u]   CHS:%03d/%d/%02d => invalid cylinder\n", m_unit, m_cylinder, m_head, m_sector);
289 		m_page = -1;
290 		return;
291 	}
292 	if (m_head < 0 || m_head >= DIABLO_HEADS) {
293 		LOG_DRIVE(0,"[DHD%u]   CHS:%03d/%d/%02d => invalid head\n", m_unit, m_cylinder, m_head, m_sector);
294 		m_page = -1;
295 		return;
296 	}
297 	if (m_sector < 0 || m_sector >= DIABLO_SPT) {
298 		LOG_DRIVE(0,"[DHD%u]   CHS:%03d/%d/%02d => invalid sector\n", m_unit, m_cylinder, m_head, m_sector);
299 		m_page = -1;
300 		return;
301 	}
302 	/* calculate the new disk relative sector offset */
303 	m_page = DIABLO_PAGE(m_cylinder, m_head, m_sector);
304 
305 	// already have the sector image?
306 	if (m_cache[m_page]) {
307 		LOG_DRIVE(9,"[DHD%u]   CHS:%03d/%d/%02d => page:%d is cached\n", m_unit, m_cylinder, m_head, m_sector, m_page);
308 		return;
309 	}
310 
311 	if (m_disk) {
312 		// allocate a buffer for this page
313 		m_cache[m_page] = std::make_unique<uint8_t[]>(sizeof(diablo_sector_t));
314 		// and read the page from the hard_disk image
315 		if (hard_disk_read(m_disk, m_page, m_cache[m_page].get())) {
316 			LOG_DRIVE(2,"[DHD%u]   CHS:%03d/%d/%02d => page:%d loaded\n", m_unit, m_cylinder, m_head, m_sector, m_page);
317 		} else {
318 			LOG_DRIVE(0,"[DHD%u]   CHS:%03d/%d/%02d => page:%d read failed\n", m_unit, m_cylinder, m_head, m_sector, m_page);
319 			m_cache[m_page] = nullptr;
320 		}
321 	} else {
322 		LOG_DRIVE(2,"[DHD%u]   no disk\n", m_unit);
323 	}
324 }
325 
326 /**
327  * @brief compute the checksum of a record
328  *
329  * @param src pointer to a record (header, label, data)
330  * @param size size of the record in bytes
331  * @param start start value for the checksum
332  * @return returns the checksum of the record
333  */
cksum(uint8_t * src,size_t size,int start)334 int diablo_hd_device::cksum(uint8_t *src, size_t size, int start)
335 {
336 	int sum = start;
337 	/* compute XOR of all words */
338 	for (size_t offs = 0; offs < size; offs += 2) {
339 		int word = src[size - 2 - offs] + 256 * src[size - 2 - offs + 1];
340 		sum ^= word;
341 	}
342 	return sum;
343 }
344 
345 /**
346  * @brief expand a series of clock bits and 0 data bits
347  *
348  * @param bits pointer to the sector bits
349  * @param dst destination offset into bits (bit number)
350  * @param size number of words to write
351  * @return offset to next destination bit
352  */
expand_zeroes(uint32_t * bits,size_t dst,size_t size)353 size_t diablo_hd_device::expand_zeroes(uint32_t *bits, size_t dst, size_t size)
354 {
355 	for (size_t offs = 0; offs < 32 * size; offs += 2) {
356 		dst = WRBIT(bits, dst, 1);      // write the clock bit
357 		dst = WRBIT(bits, dst, 0);      // write the 0 data bit
358 	}
359 	return dst;
360 }
361 
362 /**
363  * @brief expand a series of 0 words and write a final sync bit
364  *
365  * @param bits pointer to the sector bits
366  * @param dst destination offset into bits (bit number)
367  * @param size number of words to write
368  * @return offset to next destination bit
369  */
expand_sync(uint32_t * bits,size_t dst,size_t size)370 size_t diablo_hd_device::expand_sync(uint32_t *bits, size_t dst, size_t size)
371 {
372 	for (size_t offs = 0; offs < 32 * size - 2; offs += 2) {
373 		dst = WRBIT(bits, dst, 1);      // write the clock bit
374 		dst = WRBIT(bits, dst, 0);      // write the 0 data bit
375 	}
376 	dst = WRBIT(bits, dst, 1);  // write the final clock bit
377 	dst = WRBIT(bits, dst, 1);  // write the 1 data bit
378 	return dst;
379 }
380 
381 /**
382  * @brief expand a record of words into a array of bits at dst
383  *
384  * @param bits pointer to the sector bits
385  * @param dst destination offset into bits (bit number)
386  * @param field pointer to the record data (bytes)
387  * @param size size of the record in bytes
388  * @return offset to next destination bit
389  */
expand_record(uint32_t * bits,size_t dst,uint8_t * field,size_t size)390 size_t diablo_hd_device::expand_record(uint32_t *bits, size_t dst, uint8_t *field, size_t size)
391 {
392 	for (size_t offs = 0; offs < size; offs += 2) {
393 		int word = field[size - 2 - offs] + 256 * field[size - 2 - offs + 1];
394 		for (size_t bit = 0; bit < 16; bit++) {
395 			dst = WRBIT(bits, dst, 1);                  // write the clock bit
396 			dst = WRBIT(bits, dst, (word >> 15) & 1);   // write the data bit
397 			word <<= 1;
398 		}
399 	}
400 	return dst;
401 }
402 
403 /**
404  * @brief expand a record's checksum word to 32 bits
405  *
406  * @param bits pointer to the sector bits
407  * @param dst destination offset into bits (bit number)
408  * @param field pointer to the record data (bytes)
409  * @param size size of the record in bytes
410  * @return offset to next destination bit
411  */
expand_cksum(uint32_t * bits,size_t dst,uint8_t * field,size_t size)412 size_t diablo_hd_device::expand_cksum(uint32_t *bits, size_t dst, uint8_t *field, size_t size)
413 {
414 	int word = cksum(field, size, 0521);
415 	for (size_t bit = 0; bit < 32; bit += 2) {
416 		dst = WRBIT(bits, dst, 1);              // write the clock bit
417 		dst = WRBIT(bits, dst, (word >> 15) & 1);   // write the data bit
418 		word <<= 1;
419 	}
420 	return dst;
421 }
422 
423 /**
424  * @brief expand a sector into an array of clock and data bits
425  *
426  * @param page page number (0 to DRIVE_PAGES-1)
427  * @return pointer to the newly allocated array of bits
428  */
expand_sector()429 uint32_t* diablo_hd_device::expand_sector()
430 {
431 	size_t dst;
432 
433 	if (!m_bits)
434 		return nullptr;
435 	/* already expanded this sector? */
436 	if (m_bits[m_page])
437 		return m_bits[m_page].get();
438 
439 	/* allocate a sector buffer */
440 	if (!m_cache[m_page]) {
441 		LOG_DRIVE(0,"[DHD%u]   no image for page #%d\n", m_unit, m_page);
442 		return nullptr;
443 	}
444 	diablo_sector_t *s = reinterpret_cast<diablo_sector_t *>(m_cache[m_page].get());
445 
446 	/* allocate a bits image */
447 	m_bits[m_page] = make_unique_clear<uint32_t[]>(400);
448 	uint32_t* bits = m_bits[m_page].get();
449 
450 	if (m_diablo31) {
451 		/* write sync bit after (MFROBL-MRPAL) words - 1 bit */
452 		dst = expand_sync(bits, 0, (MFROBL - MRPAL));
453 		dst = expand_record(bits, dst, s->header, sizeof(s->header));
454 		dst = expand_cksum(bits, dst, s->header, sizeof(s->header));
455 
456 		/* write sync bit after 2 * MWPAL + 1 words - 1 bit */
457 		dst = expand_sync(bits, dst, 2 * MWPAL);
458 		dst = expand_record(bits, dst, s->label, sizeof(s->label));
459 		dst = expand_cksum(bits, dst, s->label, sizeof(s->label));
460 
461 		/* write sync bit after 2 * MWPAL + 1 words - 1 bit */
462 		dst = expand_sync(bits, dst, 2 * MWPAL);
463 		dst = expand_record(bits, dst, s->data, sizeof(s->data));
464 		dst = expand_cksum(bits, dst, s->data, sizeof(s->data));
465 
466 		/* fill MWPAL words of clock and 0 data bits */
467 		dst = expand_zeroes(bits, dst, MWPAL);
468 	} else {
469 		/* write sync bit after (MFROBL - MRPAL) words - 1 bit */
470 		dst = expand_sync(bits, 0, (MFROBL - MRPAL));
471 		dst = expand_record(bits, dst, s->header, sizeof(s->header));
472 		dst = expand_cksum(bits, dst, s->header, sizeof(s->header));
473 
474 		/* write sync bit after 2 * MWPAL words - 1 bit */
475 		dst = expand_sync(bits, dst, 2 * MWPAL);
476 		dst = expand_record(bits, dst, s->label, sizeof(s->label));
477 		dst = expand_cksum(bits, dst, s->label, sizeof(s->label));
478 
479 		/* write sync bit after 2 * MWPAL words - 1 bit */
480 		dst = expand_sync(bits, dst, 2 * MWPAL);
481 		dst = expand_record(bits, dst, s->data, sizeof(s->data));
482 		dst = expand_cksum(bits, dst, s->data, sizeof(s->data));
483 
484 		/* fill MWPAL words of clock and 0 data bits */
485 		dst = expand_zeroes(bits, dst, MWPAL);
486 	}
487 
488 	LOG_DRIVE(0,"[DHD%u]   CHS:%03d/%d/%02d #%5d bits\n", m_unit, m_cylinder, m_head, m_sector, dst);
489 	if (DIABLO_DEBUG)
490 	{
491 		dump_record(s->pageno, 0, sizeof(s->pageno), "pageno", 0);
492 		dump_record(s->header, 0, sizeof(s->header), "header", 0);
493 		dump_record(s->label, 0, sizeof(s->label), "label", 0);
494 		dump_record(s->data, 0, sizeof(s->data), "data", 1);
495 	}
496 	return bits;
497 }
498 
dump_ascii(uint8_t * src,size_t size)499 void diablo_hd_device::dump_ascii(uint8_t *src, size_t size)
500 {
501 	size_t offs;
502 	LOG_DRIVE(0," [");
503 	for (offs = 0; offs < size; offs++) {
504 		char ch = char(src[offs ^ 1]);
505 		LOG_DRIVE(0, "%c", ch < 32 || ch > 126 ? '.' : ch);
506 	}
507 	LOG_DRIVE(0,"]\n");
508 }
509 
510 
511 /**
512  * @brief dump a record's contents
513  *
514  * @param src pointer to a record (header, label, data)
515  * @param size size of the record in bytes
516  * @param name name to print before the dump
517  */
dump_record(uint8_t * src,size_t addr,size_t size,const char * name,int cr)518 size_t diablo_hd_device::dump_record(uint8_t *src, size_t addr, size_t size, const char *name, int cr)
519 {
520 	size_t offs;
521 	LOG_DRIVE(0,"%s:", name);
522 	for (offs = 0; offs < size; offs += 2) {
523 		int word = src[offs] + 256 * src[offs + 1];
524 		if (offs % 16) {
525 			LOG_DRIVE(0," %06o", word);
526 		} else {
527 			if (offs > 0)
528 				dump_ascii(&src[offs-16], 16);
529 			LOG_DRIVE(0,"\t%05o: %06o", (addr + offs) / 2, word);
530 		}
531 	}
532 	if (offs % 16) {
533 		dump_ascii(&src[offs - (offs % 16)], offs % 16);
534 	} else {
535 		dump_ascii(&src[offs-16], 16);
536 	}
537 	if (cr) {
538 		LOG_DRIVE(0,"\n");
539 	}
540 	return size;
541 }
542 
543 /**
544  * @brief find a sync bit in an array of clock and data bits
545  *
546  * @param bits pointer to the sector's bits
547  * @param src source index into bits (bit number)
548  * @param size number of words to scan for a sync word
549  * @return next source index for reading
550  */
squeeze_sync(uint32_t * bits,size_t src,size_t size)551 size_t diablo_hd_device::squeeze_sync(uint32_t *bits, size_t src, size_t size)
552 {
553 	uint32_t accu = 0;
554 	/* hunt for the first 0x0001 word */
555 	for (size_t bitcount = 0, offs = 0; offs < size; /* */) {
556 		/*
557 		 * accumulate clock and data bits until we are
558 		 * on the clock bit boundary
559 		 */
560 		int bit;
561 		src = RDBIT(bits,src,bit);
562 		accu = (accu << 1) | bit;
563 		/*
564 		 * look for 15 alternating clocks and 0-bits
565 		 * and the 16th clock with a 1-bit
566 		 */
567 		if (accu == 0xaaaaaaab)
568 			return src;
569 		if (++bitcount == 32) {
570 			bitcount = 0;
571 			offs++;
572 		}
573 	}
574 	/* return if no sync found within size*32 clock and data bits */
575 	LOG_DRIVE(0,"[DHD%u]   no sync within %d words\n", m_unit, size);
576 	return src;
577 }
578 
579 /**
580  * @brief find a 16 x 0 bits sequence in an array of clock and data bits
581  *
582  * @param bits pointer to the sector's bits
583  * @param src source index into bits (bit number)
584  * @param size number of words to scan for a sync word
585  * @return next source index for reading
586  */
squeeze_unsync(uint32_t * bits,size_t src,size_t size)587 size_t diablo_hd_device::squeeze_unsync(uint32_t *bits, size_t src, size_t size)
588 {
589 	uint32_t accu = 0;
590 	/* hunt for the first 0 word (16 x 0 bits) */
591 	for (size_t bitcount = 0, offs = 0; offs < size; /* */) {
592 		/*
593 		 * accumulate clock and data bits until we are
594 		 * on the clock bit boundary
595 		 */
596 		int bit;
597 		src = RDBIT(bits,src,bit);
598 		accu = (accu << 1) | bit;
599 		/*
600 		 * look for 16 alternating clocks and 0 data bits
601 		 */
602 		if (accu == 0xaaaaaaaa)
603 			return src;
604 		if (++bitcount == 32) {
605 			bitcount = 0;
606 			offs++;
607 		}
608 	}
609 	/* return if no sync found within size*32 clock and data bits */
610 	LOG_DRIVE(0,"[DHD%u]   no unsync within %d words\n", m_unit, size);
611 	return src;
612 }
613 
614 /**
615  * @brief squeeze an array of clock and data bits into a sector's record
616  *
617  * @param bits pointer to the sector's bits
618  * @param src source index into bits (bit number)
619  * @param field pointer to the record data (bytes)
620  * @param size size of the record in bytes
621  * @return next source index for reading
622  */
squeeze_record(uint32_t * bits,size_t src,uint8_t * field,size_t size)623 size_t diablo_hd_device::squeeze_record(uint32_t *bits, size_t src, uint8_t *field, size_t size)
624 {
625 	uint32_t accu = 0;
626 	for (size_t bitcount = 0, offs = 0; offs < size; /* */) {
627 		int bit;
628 		src = RDBIT(bits,src,bit);      // skip clock
629 		assert(bit == 1);
630 		src = RDBIT(bits,src,bit);      // get data bit
631 		accu = (accu << 1) | bit;
632 		bitcount += 2;
633 		if (bitcount == 32) {
634 			/* collected a word */
635 			field[size - 2 - offs + 0] = accu % 256;
636 			field[size - 2 - offs + 1] = accu / 256;
637 			offs += 2;
638 			bitcount = 0;
639 		}
640 	}
641 	return src;
642 }
643 
644 /**
645  * @brief squeeze an array of 32 clock and data bits into a checksum word
646  *
647  * @param bits pointer to the sector's bits
648  * @param src source index into bits (bit number)
649  * @param cksum pointer to an int to receive the checksum word
650  * @return next source index for reading
651  */
squeeze_cksum(uint32_t * bits,size_t src,int * cksum)652 size_t diablo_hd_device::squeeze_cksum(uint32_t *bits, size_t src, int *cksum)
653 {
654 	uint32_t accu = 0;
655 
656 	for (size_t bitcount = 0; bitcount < 32; bitcount += 2) {
657 		int bit;
658 		src = RDBIT(bits,src,bit);      // skip clock
659 		assert(bit == 1);
660 		src = RDBIT(bits,src,bit);      // get data bit
661 		accu = (accu << 1) | bit;
662 	}
663 
664 	/* set the cksum to the extracted word */
665 	*cksum = accu;
666 	return src;
667 }
668 
669 /**
670  * @brief squeeze a array of clock and data bits into a sector's data
671  *
672  * Find and squeeze header, label and data fields and verify for
673  * zero checksums, starting with a value of 0521.
674  * Write the page back to the media and free the bitmap
675  */
squeeze_sector()676 void diablo_hd_device::squeeze_sector()
677 {
678 	diablo_sector_t *s;
679 	size_t src;
680 	int cksum_header, cksum_label, cksum_data;
681 
682 	if (m_rdfirst >= 0) {
683 		LOG_DRIVE(0, "[DHD%u]  READ CHS:%03d/%d/%02d bit#%d ... bit#%d\n",
684 					m_unit, m_cylinder, m_head, m_sector, m_rdfirst, m_rdlast);
685 	}
686 	m_rdfirst = -1;
687 	m_rdlast = -1;
688 
689 	/* not written to, just drop it now */
690 	if (m_wrfirst < 0) {
691 		m_wrfirst = -1;
692 		m_wrlast = -1;
693 		return;
694 	}
695 
696 	/* did write into the next sector (?) */
697 	if (m_wrlast > m_wrfirst && m_wrlast < 256) {
698 		m_wrfirst = -1;
699 		m_wrlast = -1;
700 		return;
701 	}
702 
703 	if (m_wrfirst >= 0) {
704 		LOG_DRIVE(0, "[DHD%u]  WRITE CHS:%03d/%d/%02d bit#%d ... bit#%d\n",
705 					m_unit, m_cylinder, m_head, m_sector, m_wrfirst, m_wrlast);
706 	}
707 	m_wrfirst = -1;
708 	m_wrlast = -1;
709 
710 	if (m_page < 0 || m_page >= m_pages) {
711 		LOG_DRIVE(0,"[DHD%u]   page not set\n", m_unit);
712 		return;
713 	}
714 
715 	if (!m_cache[m_page]) {
716 		LOG_DRIVE(0,"[DHD%u]   no image\n", m_unit);
717 		return;
718 	}
719 
720 	/* no bits to write? */
721 	if (!m_bits[m_page]) {
722 		LOG_DRIVE(0,"[DHD%u]   no bits\n", m_unit);
723 		return;
724 	}
725 	uint32_t *bits = m_bits[m_page].get();
726 
727 	// pointer to sector buffer
728 	s = reinterpret_cast<diablo_sector_t *>(m_cache[m_page].get());
729 
730 	// zap the sector first
731 	memset(s, 0, sizeof(*s));
732 
733 	src = MFRRDL * 32;
734 	src = squeeze_unsync(bits, src, 40);        // skip first words and garbage until 0 bits are coming in
735 	src = squeeze_sync(bits, src, 40);          // sync on header preamble
736 	LOG_DRIVE(0,"[DHD%u]   header sync bit #%5d\n", m_unit, src);
737 	src = squeeze_record(bits, src, s->header, sizeof(s->header));
738 	LOG_DRIVE(0,"[DHD%u]   header CRC bit #%5d\n", m_unit, src);
739 	src = squeeze_cksum(bits, src, &cksum_header);
740 	if (DIABLO_DEBUG)
741 		dump_record(s->header, 0, sizeof(s->header), "header", 0);
742 
743 	src = squeeze_unsync(bits, src, 40);        // skip garbage until 0 bits are coming in
744 	src = squeeze_sync(bits, src, 40);          // sync on label preamble
745 	LOG_DRIVE(0,"[DHD%u]   label sync bit #%5d\n", m_unit, src);
746 	src = squeeze_record(bits, src, s->label, sizeof(s->label));
747 	LOG_DRIVE(0,"[DHD%u]   label CRC bit #%5d\n", m_unit, src);
748 	src = squeeze_cksum(bits, src, &cksum_label);
749 	if (DIABLO_DEBUG)
750 		dump_record(s->label, 0, sizeof(s->label), "label", 0);
751 
752 	src = squeeze_unsync(bits, src, 40);        // skip garbage until 0 bits are coming in
753 	src = squeeze_sync(bits, src, 40);          // sync on data preamble
754 	LOG_DRIVE(0,"[DHD%u]   data sync bit #%5d\n", m_unit, src);
755 	src = squeeze_record(bits, src, s->data, sizeof(s->data));
756 	LOG_DRIVE(0,"[DHD%u]   data CRC bit #%5d\n", m_unit, src);
757 	src = squeeze_cksum(bits, src, &cksum_data);
758 	if (DIABLO_DEBUG)
759 		dump_record(s->data, 0, sizeof(s->data), "data", 1);
760 	LOG_DRIVE(0,"[DHD%u]   postamble bit #%5d\n", m_unit, src);
761 
762 	/* The checksum start value always seems to be 0521 */
763 	cksum_header ^= cksum(s->header, sizeof(s->header), 0521);
764 	cksum_label ^= cksum(s->label, sizeof(s->label), 0521);
765 	cksum_data ^= cksum(s->data, sizeof(s->data), 0521);
766 
767 	if (cksum_header || cksum_label || cksum_data) {
768 		LOG_DRIVE(0,"[DHD%u]   cksum check - header:%06o label:%06o data:%06o\n", m_unit, cksum_header, cksum_label, cksum_data);
769 	}
770 	m_bits[m_page].reset();
771 
772 	if (m_disk) {
773 		if (!hard_disk_write(m_disk, m_page, m_cache[m_page].get())) {
774 			LOG_DRIVE(0,"[DHD%u]   write failed for page #%d\n", m_unit, m_page);
775 		}
776 	} else {
777 		LOG_DRIVE(2,"[DHD%u]   no disk\n", m_unit);
778 	}
779 }
780 
781 /**
782  * @brief return number of bit clocks for a sector (clock and data)
783  * @return number of bitclks for a sector
784  */
bits_per_sector() const785 int diablo_hd_device::bits_per_sector() const
786 {
787 	return m_diablo31 ? DIABLO31_SECTOR_BITS : DIABLO44_SECTOR_BITS;
788 }
789 
790 /**
791  * @brief return a pointer to a drive's description
792  * @return a pointer to the string description
793  */
description() const794 const char* diablo_hd_device::description() const
795 {
796 	return m_description;
797 }
798 
799 /**
800  * @brief return the number of a drive unit
801  * @return the unit number of this instance
802  */
unit() const803 int diablo_hd_device::unit() const
804 {
805 	return m_unit;
806 }
807 
808 /**
809  * @brief return the time for a full rotation
810  * @return the time for a full track rotation in atto seconds
811  */
rotation_time() const812 attotime diablo_hd_device::rotation_time() const
813 {
814 	return m_rotation_time;
815 }
816 
817 /**
818  * @brief return the time for a sector
819  * @return the time for a sector in atto seconds
820  */
sector_time() const821 attotime diablo_hd_device::sector_time() const
822 {
823 	return m_sector_time;
824 }
825 
826 /**
827  * @brief return the time for a data bit
828  * @return the time in atto seconds per bit clock
829  */
bit_time() const830 attotime diablo_hd_device::bit_time() const
831 {
832 	return m_bit_time;
833 }
834 
835 /**
836  * @brief return the seek/read/write status of a drive
837  * @return the seek/read/write status for the drive unit (0:active 1:inactive)
838  */
get_seek_read_write_0() const839 int diablo_hd_device::get_seek_read_write_0() const
840 {
841 	return m_s_r_w_0;
842 }
843 
844 /**
845  * @brief return the ready status of a drive
846  * @return the ready status for the drive unit (0:ready 1:not ready)
847  */
get_ready_0() const848 int diablo_hd_device::get_ready_0() const
849 {
850 	return m_ready_0;
851 }
852 
853 /**
854  * @brief return the current sector mark status of a drive
855  *
856  * The sector mark is derived from the offset into the current sector.
857  * It is deasserted except for a short time (a few micro seconds)
858  * around each new sector.
859  *
860  * @return the current sector mark for the drive (0:active 1:inactive)
861  */
get_sector_mark_0() const862 int diablo_hd_device::get_sector_mark_0() const
863 {
864 	/* no sector marks while seeking (?) */
865 	if (m_s_r_w_0)
866 		return 1;
867 
868 	/* return the sector mark */
869 	return m_sector_mark_0;
870 }
871 
872 /**
873  * @brief return the address acknowledge state
874  * @return address acknowledge state (0:active 1:inactive)
875  */
get_addx_acknowledge_0() const876 int diablo_hd_device::get_addx_acknowledge_0() const
877 {
878 	return m_addx_acknowledge_0;
879 }
880 
881 /**
882  * @brief return the log address interlock state
883  * @return log address interlock state (0:active 1:inactive)
884  */
get_log_addx_interlock_0() const885 int diablo_hd_device::get_log_addx_interlock_0() const
886 {
887 	return m_log_addx_interlock_0;
888 }
889 
890 /**
891  * @brief return the seek incomplete state
892  * @return address acknowledge state (0:active 1:inactive)
893  */
get_seek_incomplete_0() const894 int diablo_hd_device::get_seek_incomplete_0() const
895 {
896 	return m_seek_incomplete_0;
897 }
898 
899 /**
900  * @brief return the current cylinder of a drive unit
901  *
902  * This is a convenience function.
903  * There is no such signal on the BUS.
904  *
905  * Note: The bus lines are active low
906  * The value on the BUS needs an XOR with DIABLO_CYLINDER_MASK
907  * to resemble the physical line levels.
908  *
909  * @return current cylinder number for the drive
910  */
get_cylinder() const911 int diablo_hd_device::get_cylinder() const
912 {
913 	return m_cylinder;
914 }
915 
916 /**
917  * @brief return the current head of a drive unit
918  *
919  * This is a convenience function.
920  * There is no such signal on the BUS.
921  *
922  * Note: The bus lines are active low
923  * The value on the BUS needs an XOR with DIABLO_HEAD_MASK
924  * to resemble the physical line levels.
925  *
926  * @return currently selected head for the drive
927  */
get_head() const928 int diablo_hd_device::get_head() const
929 {
930 	return m_head;
931 }
932 
933 /**
934  * @brief return the current sector of a drive unit
935  *
936  * The current sector number is derived from the time since the
937  * most recent track rotation started.
938  * It counts modulo DIABLO_SPT (12).
939  *
940  * Note: The bus lines are active low
941  * The value on the BUS needs an XOR with DIABLO_SECTOR_MASK
942  * to resemble the physical line levels.
943  *
944  * @return current sector for the drive
945  */
get_sector() const946 int diablo_hd_device::get_sector() const
947 {
948 	return m_sector;
949 }
950 
951 /**
952  * @brief return the current page of a drive unit
953  *
954  * This is a convenience function.
955  * There is no such signal on the BUS.
956  *
957  * The current page number is derived from the cylinder,
958  * head, and sector numbers.
959  *
960  * @return the current page for the drive
961  */
get_page() const962 int diablo_hd_device::get_page() const
963 {
964 	return m_page;
965 }
966 
967 /**
968  * @brief select a drive unit
969  *
970  * Selecting a drive unit updates the ready status
971  *
972  * @param unit unit number
973  */
select(int unit)974 void diablo_hd_device::select(int unit)
975 {
976 	assert(unit == m_unit); // this drive is selected
977 
978 	if (m_disk) {
979 		m_ready_0 = 0;                  // it is ready
980 		m_s_r_w_0 = 0;                  // and can take seek/read/write commands
981 		m_addx_acknowledge_0 = 0;       // assert address acknowledge (?)
982 		m_log_addx_interlock_0 = 1;     // deassert log address interlock (?)
983 		LOG_DRIVE(1,"[DHD%u]   select unit:%d ready\n", m_unit, unit);
984 		read_sector();
985 	} else {
986 		m_ready_0 = 1;                  // it is not ready (?)
987 		m_s_r_w_0 = 1;                  // can't take seek/read/write commands (?)
988 		m_addx_acknowledge_0 = 0;       // assert address acknowledge (?)
989 		m_log_addx_interlock_0 = 1;     // deassert log address interlock (?)
990 		LOG_DRIVE(1,"[DHD%u]   select unit:%d not ready (no image)\n", m_unit, unit);
991 	}
992 }
993 
994 /**
995  * @brief set the selected head
996  * @param head head number
997  */
set_head(int head)998 void diablo_hd_device::set_head(int head)
999 {
1000 	if ((head & DIABLO_HEAD_MASK) != m_head) {
1001 		m_head = head & DIABLO_HEAD_MASK;
1002 		LOG_DRIVE(0,"[DHD%u]   select head:%d\n", m_unit, m_head);
1003 	}
1004 }
1005 
1006 /**
1007  * @brief set the cylinder number to seek to
1008  *
1009  * This defines the cylinder to seek when the
1010  * STROBE line is pulsed.
1011  *
1012  * @param cylinder cylinder number (bus lines CYL[0-9])
1013  */
set_cylinder(int cylinder)1014 void diablo_hd_device::set_cylinder(int cylinder)
1015 {
1016 	if ((cylinder & DIABLO_CYLINDER_MASK) != m_seekto) {
1017 		m_seekto = cylinder & DIABLO_CYLINDER_MASK;
1018 		LOG_DRIVE(0,"[DHD%u]   seek to cylinder:%d\n", m_unit, m_seekto);
1019 	}
1020 }
1021 
1022 /**
1023  * @brief set the restore line
1024  *
1025  * If the restore line is asserted when the
1026  * STROBE line is pulsed, the drive seeks
1027  * towards cylinder 0.
1028  *
1029  * @param restore state of the restore line
1030  */
set_restore(int restore)1031 void diablo_hd_device::set_restore(int restore)
1032 {
1033 	if ((restore & 1) != m_restore) {
1034 		m_restore = restore & 1;
1035 		LOG_DRIVE(0,"[DHD%u]   restore:%d\n", m_unit, m_restore);
1036 	}
1037 }
1038 
1039 /**
1040  * @brief strobe a seek operation
1041  *
1042  * Seek to the specified cylinder m_seekto,
1043  * or restore to cylinder 0, if m_restore is set.
1044  *
1045  * @param strobe current level of the strobe signal (for edge detection)
1046  */
set_strobe(int strobe)1047 void diablo_hd_device::set_strobe(int strobe)
1048 {
1049 	int seekto = m_restore ? 0 : m_seekto;
1050 	if (strobe) {
1051 		LOG_DRIVE(1,"[DHD%u]   STROBE end of interlock\n", m_unit);
1052 		// deassert the log address interlock
1053 		m_log_addx_interlock_0 = 1;
1054 		return;
1055 	}
1056 
1057 	// assert the log address interlock
1058 	m_log_addx_interlock_0 = 0;
1059 
1060 	if (seekto == m_cylinder) {
1061 		LOG_DRIVE(1,"[DHD%u]   STROBE to cylinder %d acknowledge\n", m_unit, seekto);
1062 		m_addx_acknowledge_0 = 0;   // address acknowledge, if cylinder is reached
1063 		m_seek_incomplete_0 = 1;    // reset seek incomplete
1064 		return;
1065 	}
1066 	// assert the seek-read-write signal
1067 	m_s_r_w_0 = 0;
1068 
1069 	bool complete = true;
1070 	if (seekto < m_cylinder) {
1071 		m_cylinder--;                   // previous cylinder
1072 		if (m_cylinder < 0) {
1073 			m_cylinder = 0;
1074 			complete = false;
1075 		}
1076 	}
1077 	if (seekto > m_cylinder) {
1078 		/* increment cylinder */
1079 		m_cylinder++;
1080 		if (m_cylinder >= m_cylinders) {
1081 			m_cylinder = m_cylinders - 1;
1082 			complete = false;
1083 		}
1084 	}
1085 	if (complete) {
1086 		LOG_DRIVE(1,"[DHD%u]   STROBE to cylinder %d (now %d) - interlock\n", m_unit, seekto, m_cylinder);
1087 		m_addx_acknowledge_0 = 1;   // deassert address acknowledge signal
1088 		m_seek_incomplete_0 = 1;    // deassert seek incomplete signal
1089 		read_sector();
1090 	} else {
1091 		m_log_addx_interlock_0 = 0; // deassert the log address interlock signal
1092 		m_seek_incomplete_0 = 1;    // deassert seek incomplete signal
1093 		m_addx_acknowledge_0 = 0;   // assert address acknowledge signal
1094 		LOG_DRIVE(1,"[DHD%u]   STROBE to cylinder %d incomplete\n", m_unit, seekto);
1095 	}
1096 }
1097 
1098 /**
1099  * @brief set the drive erase gate
1100  * @param gate value of erase gate
1101  */
set_egate(int gate)1102 void diablo_hd_device::set_egate(int gate)
1103 {
1104 	m_egate_0 = gate & 1;
1105 }
1106 
1107 /**
1108  * @brief set the drive write gate
1109  * @param gate value of write gate
1110  */
set_wrgate(int gate)1111 void diablo_hd_device::set_wrgate(int gate)
1112 {
1113 	m_wrgate_0 = gate & 1;
1114 }
1115 
1116 /**
1117  * @brief set the drive read gate
1118  * @param gate value of read gate
1119  */
set_rdgate(int gate)1120 void diablo_hd_device::set_rdgate(int gate)
1121 {
1122 	m_rdgate_0 = gate & 1;
1123 }
1124 
1125 /**
1126  * @brief write the sector relative bit at index
1127  *
1128  * The disk controller writes a combined clock and data pulse to one output
1129  * <PRE>
1130  * Encoding of binary 01011
1131  *
1132  *   clk   data  clk   data  clk   data  clk   data  clk   data
1133  *   0     1     2     3     4     5     6     7     8     9
1134  *   +--+        +--+  +--+  +--+        +--+  +--+  +--+  +--+  +--
1135  *   |  |        |  |  |  |  |  |        |  |  |  |  |  |  |  |  |
1136  * --+  +--------+  +--+  +--+  +--------+  +--+  +--+  +--+  +--+
1137  * </PRE>
1138  *
1139  * @param index relative index of bit/clock into sector
1140  * @param wrdata write data clock or bit
1141  */
wr_data(int index,int wrdata)1142 void diablo_hd_device::wr_data(int index, int wrdata)
1143 {
1144 	if (m_wrgate_0) {
1145 		LOG_DRIVE(0,"[DHD%u]   index=%d wrgate not asserted\n", m_unit, index);
1146 		return; // write gate is not asserted (active 0)
1147 	}
1148 
1149 	if (index < 0 || index >= bits_per_sector()) {
1150 		LOG_DRIVE(0,"[DHD%u]   index=%d out of range\n", m_unit, index);
1151 		return; // don't write before or beyond the sector
1152 	}
1153 
1154 	if (-1 == m_page) {
1155 		LOG_DRIVE(0,"[DHD%u]   invalid page\n", m_unit);
1156 		return; // invalid page
1157 	}
1158 
1159 	uint32_t *bits = expand_sector();
1160 	if (!bits) {
1161 		LOG_DRIVE(0,"[DHD%u]   no bits\n", m_unit);
1162 		return; // invalid unit
1163 	}
1164 
1165 	if (-1 == m_wrfirst)
1166 		m_wrfirst = index;
1167 
1168 	LOG_DRIVE(9,"[DHD%u]   CHS:%03d/%d/%02d index #%d bit:%d\n", m_unit, m_cylinder, m_head, m_sector, index, wrdata);
1169 
1170 	if (index < GUARD_ZONE_BITS) {
1171 		/* don't write in the guard zone (?) */
1172 	} else {
1173 		WRBIT(bits,index,wrdata);
1174 	}
1175 	m_wrlast = index;
1176 }
1177 
1178 /**
1179  * @brief read the sector relative bit at index
1180  *
1181  * Note: this is a gross hack to allow the controller pulling bits
1182  * at its will, rather than clocking them with the drive's RDCLK-
1183  *
1184  * @param index is the sector relative bit index
1185  * @return returns the sector's bit by index
1186  */
rd_data(int index)1187 int diablo_hd_device::rd_data(int index)
1188 {
1189 	int bit = 0;
1190 
1191 	if (m_rdgate_0) {
1192 		LOG_DRIVE(1,"[DHD%u]   index=%d rdgate not asserted\n", m_unit, index);
1193 		return 0;   // read gate is not asserted (active 0)
1194 	}
1195 
1196 	if (index < 0 || index >= bits_per_sector()) {
1197 		LOG_DRIVE(0,"[DHD%u]   index=%d out of range\n", m_unit, index);
1198 		return 1;   // don't read before or beyond the sector
1199 	}
1200 
1201 	if (0 == m_sector_mark_0) {
1202 		LOG_DRIVE(0,"[DHD%u]   read while sector mark is asserted\n", m_unit);
1203 		return 1;   // no data while sector mark is asserted
1204 	}
1205 
1206 	if (-1 == m_page) {
1207 		LOG_DRIVE(0,"[DHD%u]   invalid page\n", m_unit);
1208 		return 1;   // invalid unit
1209 	}
1210 
1211 	uint32_t *bits = expand_sector();
1212 	if (!bits) {
1213 		LOG_DRIVE(0,"[DHD%u]   no bits\n", m_unit);
1214 		return 1;   // invalid page
1215 	}
1216 
1217 	if (-1 == m_rdfirst)
1218 		m_rdfirst = index;
1219 
1220 	RDBIT(bits,index,bit);
1221 	LOG_DRIVE(9,"[DHD%u]   CHS:%03d/%d/%02d index #%d bit:%d\n", m_unit, m_cylinder, m_head, m_sector, index, bit);
1222 	m_rdlast = index;
1223 	return bit;
1224 }
1225 
1226 /**
1227  * @brief get the sector relative clock at index
1228  *
1229  * Note: this is a gross hack to allow the controller pulling bits
1230  * at its will, rather than clocking them with the drive's RDCLK-
1231  *
1232  * @param index is the sector relative bit index
1233  * @return returns the sector's clock bit by index
1234  */
rd_clock(int index)1235 int diablo_hd_device::rd_clock(int index)
1236 {
1237 	int clk = 0;
1238 
1239 	if (index < 0 || index >= bits_per_sector()) {
1240 		LOG_DRIVE(0,"[DHD%u]   index out of range (%d)\n", m_unit, index);
1241 		return 1;   // don't read before or beyond the sector
1242 	}
1243 
1244 	if (0 == m_sector_mark_0) {
1245 		LOG_DRIVE(0,"[DHD%u]   read while sector mark is asserted\n", m_unit);
1246 		return 1;   // no clock while sector mark is low (?)
1247 	}
1248 
1249 	if (-1 == m_page) {
1250 		LOG_DRIVE(0,"[DHD%u]   invalid page\n", m_unit);
1251 		return 1;   // invalid page
1252 	}
1253 
1254 	uint32_t *bits = expand_sector();
1255 	if (!bits) {
1256 		LOG_DRIVE(0,"[DHD%u]   no bits\n", m_unit);
1257 		return 1;   // invalid unit
1258 	}
1259 
1260 	if (-1 == m_rdfirst)
1261 		m_rdfirst = index;
1262 
1263 	if (index & 1) {
1264 		// clock bits are on even bit positions only
1265 		clk = 0;
1266 	} else if (bits) {
1267 		RDBIT(bits,index,clk);
1268 	} else {
1269 		clk = 0;
1270 	}
1271 	LOG_DRIVE(9,"[DHD%u]   CHS:%03d/%d/%02d index #%d clk:%d\n", m_unit, m_cylinder, m_head, m_sector, index, clk);
1272 	m_rdlast = index;
1273 	return clk ^ 1;
1274 }
1275 
1276 /**
1277  * @brief deassert the sector mark
1278  *
1279  */
sector_mark_1()1280 void diablo_hd_device::sector_mark_1()
1281 {
1282 	LOG_DRIVE(9,"[DHD%u]   CHS:%03d/%d/%02d sector_mark_0=1\n", m_unit, m_cylinder, m_head, m_sector);
1283 	m_sector_mark_0 = 1;    // deassert sector mark (set to 1)
1284 }
1285 
1286 /**
1287  * @brief assert the sector mark and read the next sector
1288  *
1289  * Assert the sector mark and reset the read and write
1290  * first and last bit indices.
1291  * Increment the sector number, wrap and read the
1292  * next sector from the media.
1293  */
sector_mark_0()1294 void diablo_hd_device::sector_mark_0()
1295 {
1296 	LOG_DRIVE(9,"[DHD%u]   CHS:%03d/%d/%02d sector_mark_0=0\n", m_unit, m_cylinder, m_head, m_sector);
1297 
1298 	// HACK: deassert wrgate
1299 	//  m_wrgate_0 = 1;
1300 
1301 	squeeze_sector();       // squeeze previous sector bits, if it was written to
1302 	m_sector_mark_0 = 0;    // assert sector mark (set to 0)
1303 	// reset read and write bit locations
1304 	m_rdfirst = -1;
1305 	m_rdlast = -1;
1306 	m_wrfirst = -1;
1307 	m_wrlast = -1;
1308 
1309 	// count up the sector number
1310 	m_sector = (m_sector + 1) % DIABLO_SPT;
1311 	read_sector();
1312 }
1313 
device_start()1314 void diablo_hd_device::device_start()
1315 {
1316 	m_image = static_cast<diablo_image_device *>(subdevice("drive"));
1317 
1318 	m_packs = 1;        // FIXME: get from configuration?
1319 	m_unit = strstr(m_image->tag(), "diablo0") ? 0 : 1;
1320 	m_timer = timer_alloc(1, nullptr);
1321 }
1322 
device_reset()1323 void diablo_hd_device::device_reset()
1324 {
1325 	// free previous page cache
1326 	for (int page = 0; page < m_pages; page++)
1327 		if (m_cache[page])
1328 			m_cache[page] = nullptr;
1329 	// free previous bits cache
1330 	m_bits.reset();
1331 	m_handle = m_image->get_chd_file();
1332 	m_diablo31 = true;  // FIXME: get from m_handle meta data?
1333 	m_disk = m_image->get_hard_disk_file();
1334 	if (m_diablo31) {
1335 		snprintf(m_description, sizeof(m_description), "DIABLO31");
1336 		m_rotation_time = DIABLO31_ROTATION_TIME;
1337 		m_sector_time = DIABLO31_ROTATION_TIME / DIABLO_SPT;
1338 		m_sector_mark_0_time = DIABLO31_SECTOR_MARK_PULSE_PRE;
1339 		m_sector_mark_1_time = DIABLO31_SECTOR_MARK_PULSE_PRE;
1340 		m_bit_time = DIABLO31_BIT_TIME(1);
1341 		m_cylinders = DIABLO_CYLINDERS;
1342 		m_pages = DIABLO_PAGES;
1343 	} else {
1344 		snprintf(m_description, sizeof(m_description), "DIABLO44");
1345 		m_rotation_time = DIABLO44_ROTATION_TIME;
1346 		m_sector_time = DIABLO44_ROTATION_TIME / DIABLO_SPT;
1347 		m_sector_mark_0_time = DIABLO44_SECTOR_MARK_PULSE_PRE;
1348 		m_sector_mark_1_time = DIABLO44_SECTOR_MARK_PULSE_PRE;
1349 		m_bit_time = DIABLO44_BIT_TIME(1);
1350 		m_cylinders = 2 * DIABLO_CYLINDERS;
1351 		m_pages = 2 * DIABLO_PAGES;
1352 	}
1353 	LOG_DRIVE(0,"[DHD%u]   m_handle            : %p\n", m_unit, reinterpret_cast<void const *>(m_handle));
1354 	LOG_DRIVE(0,"[DHD%u]   m_disk              : %p\n", m_unit, reinterpret_cast<void const *>(m_disk));
1355 	LOG_DRIVE(0,"[DHD%u]   rotation time       : %.0fns\n", m_unit, m_rotation_time.as_double() * ATTOSECONDS_PER_NANOSECOND);
1356 	LOG_DRIVE(0,"[DHD%u]   sector time         : %.0fns\n", m_unit, m_sector_time.as_double() * ATTOSECONDS_PER_NANOSECOND);
1357 	LOG_DRIVE(0,"[DHD%u]   sector mark 0 time  : %.0fns\n", m_unit, m_sector_mark_0_time.as_double() * ATTOSECONDS_PER_NANOSECOND);
1358 	LOG_DRIVE(0,"[DHD%u]   sector mark 1 time  : %.0fns\n", m_unit, m_sector_mark_1_time.as_double() * ATTOSECONDS_PER_NANOSECOND);
1359 	LOG_DRIVE(0,"[DHD%u]   bit time            : %.0fns\n", m_unit, m_bit_time.as_double() * ATTOSECONDS_PER_NANOSECOND);
1360 
1361 	m_s_r_w_0 = 1;                  // deassert seek/read/write ready
1362 	m_ready_0 = 1;                  // deassert drive ready
1363 	m_sector_mark_0 = 1;            // deassert sector mark
1364 	m_addx_acknowledge_0 = 1;       // deassert drive address acknowledge
1365 	m_log_addx_interlock_0 = 1;     // deassert drive log address interlock
1366 	m_seek_incomplete_0 = 1;        // deassert drive seek incomplete
1367 
1368 	// reset the disk drive's strobe info
1369 	m_seekto = 0;
1370 	m_restore = 0;
1371 	// reset the disk drive's address
1372 	m_cylinder = 0;
1373 	m_head = 0;
1374 	m_sector = 0;
1375 	m_page = 0;
1376 
1377 	// disable the erase, write and read gates
1378 	m_egate_0 = 1;
1379 	m_wrgate_0 = 1;
1380 	m_rdgate_0 = 1;
1381 
1382 	// reset read and write first and last indices
1383 	m_wrfirst = -1;
1384 	m_wrlast = -1;
1385 	m_rdfirst = -1;
1386 	m_rdlast = -1;
1387 
1388 	if (!m_handle)
1389 		return;
1390 	// for units with a CHD assigned to them start the timer
1391 	m_bits = std::make_unique<std::unique_ptr<uint32_t[]>[]>(m_pages);
1392 	timer_set(m_sector_time - m_sector_mark_0_time, 1, 0);
1393 	read_sector();
1394 }
1395 
1396 /**
1397  * @brief timer callback that is called thrice per sector in the rotation
1398  *
1399  * The timer is called three times at the events:
1400  * 0: sector mark goes active
1401  * 1: sector mark goes inactive
1402  * 2: in the middle of the active phase
1403  *
1404  * @param id timer id
1405  * @param arg argument supplied to timer_insert (unused)
1406  */
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)1407 void diablo_hd_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
1408 {
1409 	LOG_DRIVE(9,"[DHD%u]   TIMER id=%d param=%d ptr=%p @%.0fns\n", m_unit, id, param, ptr, timer.elapsed().as_double() * ATTOSECONDS_PER_NANOSECOND);
1410 	if (!m_disk)
1411 		return;
1412 
1413 	switch (param) {
1414 	case 0:
1415 		// assert sector mark
1416 		sector_mark_0();
1417 		// next sector timer event is in the middle between sector_mark going 0 and back to 1
1418 		timer.adjust(m_sector_mark_0_time, 1);
1419 		break;
1420 	case 1:
1421 		/* call the sector_callback, if any */
1422 		if (m_sector_callback)
1423 			(void)(*m_sector_callback)(m_sector_callback_cookie, m_unit);
1424 		// next sector timer event is deassert of sector_mark_0 (set to 1)
1425 		timer.adjust(m_sector_mark_1_time, 2);
1426 		break;
1427 	case 2:
1428 		// deassert sector mark
1429 		sector_mark_1();
1430 		// next sector timer event is sector_mark_0 for next sector
1431 		timer.adjust(m_sector_time - m_sector_mark_0_time, 0);
1432 		break;
1433 	}
1434 }
1435 
device_add_mconfig(machine_config & config)1436 void diablo_hd_device::device_add_mconfig(machine_config &config)
1437 {
1438 	DIABLO(config, "drive", 0);
1439 }
1440 
1441 
1442 DEFINE_DEVICE_TYPE(DIABLO_HD, diablo_hd_device, "diablo_hd", "Diablo Disk")
1443