Previous 199869 Revisions Next

r26125 Tuesday 12th November, 2013 at 20:37:01 UTC by Jürgen Buchmüller
Moved diablo_hd.c/h code to src/emu/machine. Linking works while there will be crashes until everything is cleaned up and tested.
[/branches/alto2/src/emu]emu.mak
[/branches/alto2/src/emu/machine]diablo_hd.c* diablo_hd.h*
[/branches/alto2/src/emu/sound]nes_defs.h
[/branches/alto2/src/mess]mess.mak
[/branches/alto2/src/mess/machine]diablo_hd.c diablo_hd.h

branches/alto2/src/emu/sound/nes_defs.h
r26124r26125
100100         }
101101         vbl_length =0;
102102         freq = 0;
103         phaseacc = 0.0d;
104         output_vol = 0.0d;
105         env_phase = 0.0d;
106         sweep_phase = 0.0d;
103         phaseacc = 0.0;
104         output_vol = 0.0;
105         env_phase = 0.0;
106         sweep_phase = 0.0;
107107         adder = 0;
108108         env_vol = 0;
109109         enabled = false;
r26124r26125
133133         linear_length =0;
134134         vbl_length =0;
135135         write_latency = 0;
136         phaseacc = 0.0d;
137         output_vol = 0.0d;
136         phaseacc = 0.0;
137         output_vol = 0.0;
138138         adder = 0;
139139         counter_started = false;
140140         enabled = false;
r26124r26125
162162         }
163163         cur_pos =0;
164164         vbl_length =0;
165         phaseacc = 0.0d;
166         output_vol = 0.0d;
167         env_phase = 0.0d;
165         phaseacc = 0.0;
166         output_vol = 0.0;
167         env_phase = 0.0;
168168         env_vol = 0;
169169         enabled = false;
170170      }
r26124r26125
191191      address = 0;
192192      length = 0;
193193      bits_left = 0;
194      phaseacc = 0.0d;
195      output_vol = 0.0d;
194      phaseacc = 0.0;
195      output_vol = 0.0;
196196      cur_byte = 0;
197197      enabled = false;
198198      irq_occurred = false;
branches/alto2/src/emu/emu.mak
r26124r26125
185185   $(EMUMACHINE)/ram.o         \
186186   $(EMUMACHINE)/nvram.o       \
187187   $(EMUMACHINE)/laserdsc.o    \
188   $(EMUMACHINE)/diablo_hd.o   \
188189   $(EMUMACHINE)/netlist.o     \
189190
190191EMUIMAGEDEVOBJS = \
branches/alto2/src/emu/machine/diablo_hd.c
r0r26125
1/**********************************************************
2 *   DIABLO31 and DIABLO44 hard drive support
3 *
4 *   Copyright: Juergen Buchmueller <pullmoll@t-online.de>
5 *
6 *   Licenses: MAME, GPLv2
7 **********************************************************/
8
9#include "diablo_hd.h"
10
11/**
12 *
13 * Just for completeness' sake:
14 * The mapping of disk controller connector P2 pins to the
15 * Winchester disk drive signals (see drive.h)
16 * <PRE>
17 * Alto Controller     Winchester
18 * P2 signal           disk bus
19 * -----------------------------------------------
20 *  1 GND              D_GROUND
21 *  2 RDCLK'           A_READ_CLOCK
22 *  3 WRDATA'          B_WRITE_DATA_AND_CLOCK
23 *  4 SRWRDY'          F_S_R_W
24 *  5 DISK             L_SELECT_LINE_UNIT_1
25 *  6 CYL(7)'          N_CYL_7
26 *  7 DISK'            R_SELECT_LINE_UNIT_2
27 *  8 CYL(2)'          T_CYL_2
28 *  9 ???              V_SELECT_LINE_UNIT_3
29 * 10 CYL(4)'          X_CYL_4
30 * 11 CYL(0)'          Z_CYL_0
31 * 12 CYL(1)'          BB_CYL_1
32 * 13 CYL(3)'          FF_CYL_3
33 * 14 ???              KK_BIT_2
34 * 15 CYL(8)'          LL_CYL_8
35 * 16 ADRACK'          NN_ADDX_ACKNOWLEDGE
36 * 17 SKINC'           TT_SEEK_INCOMPLETE
37 * 18 LAI'             XX_LOG_ADDX_INTERLOCK
38 * 19 CYL(6)'          RR_CYL_6
39 * 20 RESTOR'          VV_RESTORE
40 * 21 ???              UU_BIT_16
41 * 22 STROBE'          SS_STROBE
42 * 23 ???              MM_BIT_8
43 * 24 ???              KK_BIT_4
44 * 25 ???              HH_WRITE_CHK
45 * 26 WRTGATE'         EE_WRITE_GATE
46 * 27 ???              CC_BIT_SECTOR_ADDX
47 * 28 HEAD'            AA_HEAD_SELECT
48 * 29 ???              Y_INDEX_MARK
49 * 30 SECT(4)'         W_SECTOR_MARK
50 * 31 READY'           U_FILE_READY
51 * 32 ???              S_PSEUDO_SECTOR_MARK
52 * 33 ???              P_WRITE_PROTECT_IND
53 * 34 ???              H_WRITE_PROTECT_INPUT_ATTENTION
54 * 35 ERGATE'          K_ERASE_GATE
55 * 36 ???              M_HIGH_DENSITY
56 * 37 CYL(5)'          J_CYL_5
57 * 38 RDDATA'          C_READ_DATA
58 * 39 RDGATE'          E_READ_GATE
59 * 40 GND              ??
60 * </PRE>
61 */
62
63diablo_hd_device::diablo_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
64   device_t(mconfig, DIABLO_HD, "Diablo Disk", tag, owner, clock, "diablo_hd", __FILE__),
65#if   DIABLO_DEBUG
66   m_log_level(9),
67#endif
68   m_diablo31(true),
69   m_unit(0),
70   m_description(),
71   m_packs(1),
72   m_rotation_time(),
73   m_sector_time(),
74   m_sector_mark_0_time(),
75   m_sector_mark_1_time(),
76   m_bit_time(),
77   m_s_r_w_0(1),
78   m_ready_0(1),
79   m_sector_mark_0(1),
80   m_addx_acknowledge_0(1),
81   m_log_addx_interlock_0(1),
82   m_seek_incomplete_0(1),
83   m_egate_0(1),
84   m_wrgate_0(1),
85   m_rdgate_0(1),
86   m_cylinder(-1),
87   m_head(-1),
88   m_sector(-1),
89   m_page(-1),
90   m_image(),
91   m_bits(),
92   m_rdfirst(-1),
93   m_rdlast(-1),
94   m_wrfirst(-1),
95   m_wrlast(-1),
96   m_sector_callback(0),
97   m_sector_timer(0),
98   m_drive(0)
99{
100}
101
102#if   DIABLO_DEBUG
103void alto2_cpu_device::logprintf(int level, const char* format, ...)
104{
105   if (level > m_log_level)
106      return;
107   va_list ap;
108   va_start(ap, format);
109   debug_console_vprintf(machine(), format, ap);
110   va_end(ap);
111}
112#endif
113
114#define   DIABLO31_ROTATION_TIME attotime::from_msec(39.9999)      //!< DIABLO 31 rotation time is approx. 40ms
115#define   DIABLO31_SECTOR_TIME attotime::from_msec(39.9999/12)   //!< DIABLO 31 sector time
116/**
117 * @brief DIABLO 31 bit clock is 3330kHz ~= 300ns per bit
118 * ~= 133333 bits/track (?)
119 * ~= 11111 bits/sector
120 * ~= 347 words/sector
121 */
122#define   DIABLO31_BIT_TIME(bits) attotime::from_nsec(300*(bits))
123#define   DIABLO31_SECTOR_WORDS 347                        //!< DIABLO 31 possible sector words
124#define   DIABLO31_SECTOR_MARK_PULSE_PRE DIABLO31_BIT_TIME(16)   //!< pulse width of sector mark before the next sector begins
125#define   DIABLO31_SECTOR_MARK_PULSE_POST DIABLO31_BIT_TIME(16)   //!< pulse width of sector mark after the next sector began
126
127#define   DIABLO44_ROTATION_TIME attotime::from_msec(25)         //!< DIABLO 44 rotation time is approx. 25ms
128#define   DIABLO44_SECTOR_TIME   attotime::from_msec(25/12)      //!< DIABLO 44 sector time
129
130/**
131 * @brief DIABLO 44 bit clock is 5000kHz ~= 200ns per bit
132 * ~= 125184 bits/track (?)
133 * ~= 10432 bits/sector
134 * ~= 325 words/sector
135 */
136#define   DIABLO44_BIT_TIME(bits) attotime::from_nsec(200*(bits))
137#define   DIABLO44_SECTOR_WORDS   325                        //!< DIABLO 44 possible sector words
138#define   DIABLO44_SECTOR_MARK_PULSE_PRE DIABLO44_BIT_TIME(16)   //!< pulse width of sector mark before the next sector begins
139#define   DIABLO44_SECTOR_MARK_PULSE_POST DIABLO44_BIT_TIME(16)   //!< pulse width of sector mark after the next sector began
140
141#define   MFROBL         34      //!< from the microcode: disk header preamble is 34 words
142#define   MFRRDL         21      //!< from the microcode: disk header read delay is 21 words
143#define   MIRRDL         4      //!< from the microcode: interrecord read delay is 4 words
144#define   MIROBL         3      //!< from the microcode: disk interrecord preamble is 3 words
145#define   MRPAL         3      //!< from the microcode: disk read postamble length is 3 words
146#define   MWPAL         5      //!< from the microcode: disk write postamble length is 5 words
147
148#define   GUARD_ZONE_BITS   (16*32)   //!< end of the guard zone at the beginning of a sector (wild guess!)
149
150/**
151 * @brief description of the sector layout
152 * <PRE>
153 *
154 *                                   xx.x msec sector mark pulses
155 * -+   +-------------------------------------------------------------------------------+   +--
156 *  |   |                                                                               |   |
157 *  +---+                                                                               +---+
158 *
159 *    |                                                                                   |
160 *
161 *    +------+----+------+-----+------+----+-------+-----+------+----+-------+-----+------+
162 *    | PRE- |SYNC|HEADER|CKSUM| PRE- |SYNC| LABEL |CKSUM| PRE- |SYNC| DATA  |CKSUM| POST |
163 *    |AMBLE1|  1 |      |  1  |AMBLE2|  2 |       |  2  |AMBLE3|  3 |       |  3  |AMBLE |
164 *    +------+----+------+-----+------+----+-------+-----+------+----+-------+-----+------+
165 *
166 *    |                                                                                   |
167 *
168 *    +-----------------------------------------------------------------------------------+
169 *    |                                                                                   |
170 * ---+                                                                                   +----
171 *      FORMAT WRITE GATE FOR INITIALIZING
172 *    |                                                                                   |
173 *
174 *    |                                                    +------------------------------+
175 *                                                         |                              |
176 * ---|----------------------------------------------------+                              +----
177 *      WRITE GATE FOR DATA XFER (*)
178 *    |                                                                                   |
179 *
180 *    |                          +-----------------------+-+------------------------------+
181 *                               |                       | | may be continuous (?)        |
182 * ------------------------------+                       +-+                              +----
183 * ???  WRITE GATE FOR LABEL AND DATA XFER (*)
184 *    |                                                                                   |
185 *
186 *    |   +--------------------+   +---------------------+   +----------------------------+
187 *        |                    |   |                     |   |                            |
188 * -------+                    +---+                     +---+                            +----
189 *      READ GATE FOR INITIALIZING OR DATA XFER (**)
190 *
191 *
192 *  (*) Enable should be delayed 1 byte/word time from last bit of checks sum.
193 *  (**) Read Gate should be enabled half way through the preamble area. This
194 *       ensures reading a zero field for data separator synchronization.
195 *
196 * </PRE>
197 */
198
199#define   DIABLO_PAGENO_WORDS   1      //!< number of words in a page number (this doesn't really belong here)
200#define   DIABLO_HEADER_WORDS   2      //!< number of words in a header (this doesn't really belong here)
201#define   DIABLO_LABEL_WORDS   8      //!< number of words in a label (this doesn't really belong here)
202#define   DIABLO_DATA_WORDS   256      //!< number of data words (this doesn't really belong here)
203#define   DIABLO_CKSUM_WORDS   1      //!< number of words for a checksum (this doesn't really belong here)
204
205/**
206 * @brief format of the cooked disk image sectors, i.e. pure data
207 *
208 * The available images are a multiple of 267 words (534 bytes) per sector,
209 * 1 word page number
210 * 2 words header
211 * 8 words label
212 * 256 words data
213 */
214typedef struct {
215   UINT8 pageno[2*DIABLO_PAGENO_WORDS];   //!< sector page number
216   UINT8 header[2*DIABLO_HEADER_WORDS];   //!< sector header words
217   UINT8 label[2*DIABLO_LABEL_WORDS];      //!< sector label words
218   UINT8 data[2*DIABLO_DATA_WORDS];      //!< sector data words
219}   diablo_sector_t;
220
221/** @brief write a bit into an array of UINT32 */
222static inline size_t WRBIT(UINT32* bits, size_t dst, int bit)
223{
224   if (bit) {
225      bits[(dst)/32] |= 1 << ((dst) % 32);
226   } else {
227      bits[(dst)/32] &= ~(1 << ((dst) % 32));
228   }
229   return ++dst;
230}
231
232/** @brief read a bit from an array of UINT32 */
233static inline size_t RDBIT(UINT32* bits, size_t src, int& bit)
234{
235   bit = (bits[src/32] >> (src % 32)) & 1;
236   return ++src;
237}
238
239/**
240 * @brief calculate the sector from the logical block address and read it
241 *
242 * Modifies drive's page by calculating the logical
243 * block address from cylinder, head, and sector.
244 */
245void diablo_hd_device::read_sector()
246{
247   /* If there's no drive, just reset the page number */
248   if (!m_drive) {
249      m_page = -1;
250      return;
251   }
252   if (m_cylinder < 0 || m_cylinder >= DIABLO_CYLINDERS) {
253      LOG_DRIVE((9,"   DRIVE C/H/S:%d/%d/%d => invalid cylinder\n", m_cylinder, m_head, m_sector));
254      m_page = -1;
255      return;
256   }
257   if (m_head < 0 || m_head >= DIABLO_HEADS) {
258      LOG_DRIVE((9,"   DRIVE C/H/S:%d/%d/%d => invalid head\n", m_cylinder, m_head, m_sector));
259      m_page = -1;
260      return;
261   }
262   if (m_sector < 0 || m_sector >= DIABLO_SPT) {
263      LOG_DRIVE((9,"   DRIVE C/H/S:%d/%d/%d => invalid sector\n", m_cylinder, m_head, m_sector));
264      m_page = -1;
265      return;
266   }
267   /* calculate the new disk relative sector offset */
268   m_page = DRIVE_PAGE(m_cylinder, m_head, m_sector);
269   LOG_DRIVE((9,"   DRIVE C/H/S:%d/%d/%d => page:%d\n", m_cylinder, m_head, m_sector, m_page));
270
271   // already have the sector image?
272   if (m_image[m_page])
273      return;
274
275   hard_disk_file *file = m_drive->get_hard_disk_file();
276   if (!file) {
277      LOG_DRIVE((0,"   no file for unit #%d\n", m_unit));
278      return;
279   }
280
281   /* allocate a sector buffer */
282   m_image[m_page] = global_alloc_array(UINT8, sizeof(diablo_sector_t));
283   if (!hard_disk_read(file, m_page, m_image[m_page])) {
284      LOG_DRIVE((0,"   read failed for #%d page #%d\n", m_unit, m_page));
285      global_free(m_image[m_page]);
286      m_image[m_page] = 0;
287      return;
288   }
289}
290
291/**
292 * @brief compute the checksum of a record
293 *
294 * @param src pointer to a record (header, label, data)
295 * @param size size of the record in bytes
296 * @param start start value for the checksum
297 * @return returns the checksum of the record
298 */
299int diablo_hd_device::cksum(UINT8 *src, size_t size, int start)
300{
301   int sum = start;
302   /* compute XOR of all words */
303   for (size_t offs = 0; offs < size; offs += 2) {
304      int word = src[size - 2 - offs] + 256 * src[size - 2 - offs + 1];
305      sum ^= word;
306   }
307   return sum;
308}
309
310/**
311 * @brief expand a series of clock bits and 0 data bits
312 *
313 * @param bits pointer to the sector bits
314 * @param dst destination offset into bits (bit number)
315 * @param size number of words to write
316 * @return offset to next destination bit
317 */
318size_t diablo_hd_device::expand_zeroes(UINT32 *bits, size_t dst, size_t size)
319{
320   for (size_t offs = 0; offs < 32 * size; offs += 2) {
321      dst = WRBIT(bits, dst, 1);      // write the clock bit
322      dst = WRBIT(bits, dst, 0);      // write the 0 data bit
323   }
324   return dst;
325}
326
327/**
328 * @brief expand a series of 0 words and write a final sync bit
329 *
330 * @param bits pointer to the sector bits
331 * @param dst destination offset into bits (bit number)
332 * @param size number of words to write
333 * @return offset to next destination bit
334 */
335size_t diablo_hd_device::expand_sync(UINT32 *bits, size_t dst, size_t size)
336{
337   for (size_t offs = 0; offs < 32 * size - 2; offs += 2) {
338      dst = WRBIT(bits, dst, 1);      // write the clock bit
339      dst = WRBIT(bits, dst, 0);      // write the 0 data bit
340   }
341   dst = WRBIT(bits, dst, 1);   // write the final clock bit
342   dst = WRBIT(bits, dst, 1);   // write the 1 data bit
343   return dst;
344}
345
346/**
347 * @brief expand a record of words into a array of bits at dst
348 *
349 * @param bits pointer to the sector bits
350 * @param dst destination offset into bits (bit number)
351 * @param field pointer to the record data (bytes)
352 * @param size size of the record in bytes
353 * @return offset to next destination bit
354 */
355size_t diablo_hd_device::expand_record(UINT32 *bits, size_t dst, UINT8 *field, size_t size)
356{
357   for (size_t offs = 0; offs < size; offs += 2) {
358      int word = field[size - 2 - offs] + 256 * field[size - 2 - offs + 1];
359      for (size_t bit = 0; bit < 16; bit++) {
360         dst = WRBIT(bits, dst, 1);               // write the clock bit
361         dst = WRBIT(bits, dst, (word >> 15) & 1);   // write the data bit
362         word <<= 1;
363      }
364   }
365   return dst;
366}
367
368/**
369 * @brief Expand a record's checksum word to 32 bits
370 *
371 * @param bits pointer to the sector bits
372 * @param dst destination offset into bits (bit number)
373 * @param field pointer to the record data (bytes)
374 * @param size size of the record in bytes
375 * @return offset to next destination bit
376 */
377size_t diablo_hd_device::expand_cksum(UINT32 *bits, size_t dst, UINT8 *field, size_t size)
378{
379   int word = cksum(field, size, 0521);
380   for (size_t bit = 0; bit < 32; bit += 2) {
381      dst = WRBIT(bits, dst, 1);            // write the clock bit
382      dst = WRBIT(bits, dst, (word >> 15) & 1);   // write the data bit
383      word <<= 1;
384   }
385   return dst;
386}
387
388/**
389 * @brief Expand a sector into an array of clock and data bits
390 *
391 * @param page page number (0 to DRIVE_PAGES-1)
392 */
393UINT32* diablo_hd_device::expand_sector()
394{
395   size_t dst;
396
397   /* already expanded this sector? */
398   if (m_bits[m_page])
399      return m_bits[m_page];
400
401   /* allocate a sector buffer */
402   if (!m_image[m_page]) {
403      LOG_DRIVE((0,"   no image for #%d page #%d\n", m_unit, m_page));
404      return NULL;
405   }
406   diablo_sector_t *s = reinterpret_cast<diablo_sector_t *>(m_image[m_page]);
407
408   /* allocate a bits image */
409   UINT32 *bits = reinterpret_cast<UINT32 *>(global_alloc_array(UINT32, 400));
410
411   if (m_diablo31) {
412      /* write sync bit after 31 words - 1 bit */
413      dst = expand_sync(bits, 0, 31);
414      dst = expand_record(bits, dst, s->header, sizeof(s->header));
415      dst = expand_cksum(bits, dst, s->header, sizeof(s->header));
416
417      /* write sync bit after 2 * 5 + 1 words - 1 bit */
418      dst = expand_sync(bits, dst, 2 * MWPAL);
419      dst = expand_record(bits, dst, s->label, sizeof(s->label));
420      dst = expand_cksum(bits, dst, s->label, sizeof(s->label));
421
422      /* write sync bit after 2 * 5 + 1 words - 1 bit */
423      dst = expand_sync(bits, dst, 2 * MWPAL);
424      dst = expand_record(bits, dst, s->data, sizeof(s->data));
425      dst = expand_cksum(bits, dst, s->data, sizeof(s->data));
426
427      /* fill MWPAL words of clock and 0 data bits */
428      dst = expand_zeroes(bits, dst, MWPAL);
429   } else {
430      /* write sync bit after 31 words - 1 bit */
431      dst = expand_sync(bits, 0, 31);
432      dst = expand_record(bits, dst, s->header, sizeof(s->header));
433      dst = expand_cksum(bits, dst, s->header, sizeof(s->header));
434
435      /* write sync bit after 2 * 5 words - 1 bit */
436      dst = expand_sync(bits, dst, 2 * MWPAL);
437      dst = expand_record(bits, dst, s->label, sizeof(s->label));
438      dst = expand_cksum(bits, dst, s->label, sizeof(s->label));
439
440      /* write sync bit after 2 * 5 words - 1 bit */
441      dst = expand_sync(bits, dst, 2 * MWPAL);
442      dst = expand_record(bits, dst, s->data, sizeof(s->data));
443      dst = expand_cksum(bits, dst, s->data, sizeof(s->data));
444
445      /* fill MWPAL words of clock and 0 data bits */
446      dst = expand_zeroes(bits, dst, MWPAL);
447   }
448   m_bits[m_page] = bits;
449
450   LOG_DRIVE((0,"   BITS #%d: %03d/%d/%02d #%-5d bits (@%03d.%02d)\n",
451      m_unit, m_cylinder, m_head, m_sector,
452      dst, dst / 32, dst % 32));
453
454   return bits;
455}
456
457#if   DIABLO_DEBUG
458void diablo_hd_device::drive_dump_ascii(UINT8 *src, size_t size)
459{
460   size_t offs;
461   LOG_DRIVE((0," ["));
462   for (offs = 0; offs < size; offs++) {
463      char ch = (char)src[offs ^ 1];
464      LOG_DRIVE((0, "%c", ch < 32 || ch > 126 ? '.' : ch));
465   }
466   LOG_DRIVE((0,"]\n"));
467}
468
469
470/**
471 * @brief Dump a record's contents
472 *
473 * @param src pointer to a record (header, label, data)
474 * @param size size of the record in bytes
475 * @param name name to print before the dump
476 */
477size_t diablo_hd_device::dump_record(UINT8 *src, size_t addr, size_t size, const char *name, int cr)
478{
479   size_t offs;
480   LOG_DRIVE((0,"%s:", name));
481   for (offs = 0; offs < size; offs += 2) {
482      int word = src[offs] + 256 * src[offs + 1];
483      if (offs % 16) {
484         LOG_DRIVE((0," %06o", word));
485      } else {
486         if (offs > 0)
487            drive_dump_ascii(&src[offs-16], 16);
488         LOG_DRIVE((0,"\t%05o: %06o", (addr + offs) / 2, word));
489      }
490   }
491   if (offs % 16) {
492      drive_dump_ascii(&src[offs - (offs % 16)], offs % 16);
493   } else {
494      drive_dump_ascii(&src[offs-16], 16);
495   }
496   if (cr) {
497      LOG_DRIVE((0,"\n"));
498   }
499   return size;
500}
501#endif
502
503/**
504 * @brief find a sync bit in an array of clock and data bits
505 *
506 * @param bits pointer to the sector's bits
507 * @param src source offset into bits (bit number)
508 * @param size number of words to scan for a sync word
509 * @return next source offset for reading
510 */
511size_t diablo_hd_device::squeeze_sync(UINT32 *bits, size_t src, size_t size)
512{
513   UINT32 accu = 0;
514   /* hunt for the first 0x0001 word */
515   for (size_t bitcount = 0, offs = 0; offs < size; /* */) {
516      /*
517       * accumulate clock and data bits until we are
518       * on the clock bit boundary
519       */
520      int bit;
521      src = RDBIT(bits,src,bit);
522      accu = (accu << 1) | bit;
523      /*
524       * look for 15 alternating clocks and 0-bits
525       * and the 16th clock with a 1-bit
526       */
527      if (accu == 0xaaaaaaab)
528         return src;
529      if (++bitcount == 32) {
530         bitcount = 0;
531         offs++;
532      }
533   }
534   /* return if no sync found within size*32 clock and data bits */
535   LOG_DRIVE((0,"   no sync within %d words\n", size));
536   return src;
537}
538
539/**
540 * @brief find a 16 x 0 bits sequence in an array of clock and data bits
541 *
542 * @param bits pointer to the sector's bits
543 * @param src source offset into bits (bit number)
544 * @param size number of words to scan for a sync word
545 * @return next source offset for reading
546 */
547size_t diablo_hd_device::squeeze_unsync(UINT32 *bits, size_t src, size_t size)
548{
549   UINT32 accu = 0;
550   /* hunt for the first 0 word (16 x 0 bits) */
551   for (size_t bitcount = 0, offs = 0; offs < size; /* */) {
552      /*
553       * accumulate clock and data bits until we are
554       * on the clock bit boundary
555       */
556      int bit;
557      src = RDBIT(bits,src,bit);
558      accu = (accu << 1) | bit;
559      /*
560       * look for 16 alternating clocks and 0 data bits
561       */
562      if (accu == 0xaaaaaaaa)
563         return src;
564      if (++bitcount == 32) {
565         bitcount = 0;
566         offs++;
567      }
568   }
569   /* return if no sync found within size*32 clock and data bits */
570   LOG_DRIVE((0,"   no unsync within %d words\n", size));
571   return src;
572}
573
574/**
575 * @brief squeeze an array of clock and data bits into a sector's record
576 *
577 * @param bits pointer to the sector's bits
578 * @param src source offset into bits (bit number)
579 * @param field pointer to the record data (bytes)
580 * @param size size of the record in bytes
581 * @return next source offset for reading
582 */
583size_t diablo_hd_device::squeeze_record(UINT32 *bits, size_t src, UINT8 *field, size_t size)
584{
585   UINT32 accu = 0;
586   for (size_t bitcount = 0, offs = 0; offs < size; /* */) {
587      int bit;
588      src = RDBIT(bits,src,bit);      // skip clock
589      assert(bit == 1);
590      src = RDBIT(bits,src,bit);      // get data bit
591      accu = (accu << 1) | bit;
592      bitcount += 2;
593      if (bitcount == 32) {
594         /* collected a word */
595         field[size - 2 - offs + 0] = accu % 256;
596         field[size - 2 - offs + 1] = accu / 256;
597         offs += 2;
598         bitcount = 0;
599      }
600   }
601   return src;
602}
603
604/**
605 * @brief squeeze an array of 32 clock and data bits into a checksum word
606 *
607 * @param bits pointer to the sector's bits
608 * @param src source offset into bits (bit number)
609 * @param cksum pointer to an int to receive the checksum word
610 * @return next source offset for reading
611 */
612size_t diablo_hd_device::squeeze_cksum(UINT32 *bits, size_t src, int *cksum)
613{
614   UINT32 accu = 0;
615
616   for (size_t bitcount = 0; bitcount < 32; bitcount += 2) {
617      int bit;
618      src = RDBIT(bits,src,bit);      // skip clock
619      assert(bit == 1);
620      src = RDBIT(bits,src,bit);      // get data bit
621      accu = (accu << 1) | bit;
622   }
623
624   /* set the cksum to the extracted word */
625   *cksum = accu;
626   return src;
627}
628
629/**
630 * @brief Squeeze a array of clock and data bits into a sector's data
631 */
632void diablo_hd_device::squeeze_sector()
633{
634   diablo_sector_t *s;
635   size_t src;
636   int cksum_header, cksum_label, cksum_data;
637
638   if (m_rdfirst >= 0) {
639      LOG_DRIVE((0,
640         "   RD #%d %03d/%d/%02d bit#%-5d (@%03d.%02d) ... bit#%-5d (@%03d.%02d)\n",
641         m_unit, m_cylinder, m_head, m_sector,
642         m_rdfirst, m_rdfirst / 32, m_rdfirst % 32,
643         m_rdlast, m_rdlast / 32, m_rdlast % 32));
644   }
645   m_rdfirst = -1;
646   m_rdlast = -1;
647
648   /* not written to, just drop it now */
649   if (m_wrfirst < 0) {
650      m_wrfirst = -1;
651      m_wrlast = -1;
652      return;
653   }
654
655   /* did write into the next sector (?) */
656   if (m_wrlast > m_wrfirst && m_wrlast < 256) {
657      m_wrfirst = -1;
658      m_wrlast = -1;
659      return;
660   }
661
662   if (m_wrfirst >= 0) {
663      LOG_DRIVE((0,
664         "   WR #%d %03d/%d/%02d bit#%-5d (@%03d.%02d) ... bit#%-5d (@%03d.%02d)\n",
665         m_unit, m_cylinder, m_head, m_sector,
666         m_wrfirst, m_wrfirst / 32, m_wrfirst % 32,
667         m_wrlast, m_wrlast / 32, m_wrlast % 32));
668   }
669   m_wrfirst = -1;
670   m_wrlast = -1;
671
672   if (m_page < 0 || m_page >= DIABLO_PAGES) {
673      LOG_DRIVE((0,"   no sector for #%d: %d/%d/%d\n", m_unit, m_cylinder, m_head, m_sector));
674      return;
675   }
676
677   if (!m_image[m_page]) {
678      LOG_DRIVE((0,"   no image for #%d: %d/%d/%d\n", m_unit, m_cylinder, m_head, m_sector));
679      return;
680   }
681
682   /* no bits to write? */
683   if (!m_bits[m_page]) {
684      LOG_DRIVE((0,"   no bits for #%d: %d/%d/%d\n", m_unit, m_cylinder, m_head, m_sector));
685      return;
686   }
687   UINT32 *bits = m_bits[m_page];
688
689   /* pointer to sector buffer */
690   s = reinterpret_cast<diablo_sector_t *>(m_image[m_page]);
691
692   /* zap the sector first */
693   memset(s, 0, sizeof(*s));
694
695   src = MFRRDL * 32;
696   /* skip first words and garbage until 0 bits are coming in */
697   src = squeeze_unsync(bits, src, 40);
698   /* sync on header preamble */
699   src = squeeze_sync(bits, src, 40);
700   LOG_DRIVE((0,"   header sync bit #%d (@%03d.%02d)\n", src, src / 32, src % 32));
701   src = squeeze_record(bits, src, s->header, sizeof(s->header));
702   src = squeeze_cksum(bits, src, &cksum_header);
703#if   DIABLO_DEBUG
704   dump_record(s->header, 0, sizeof(s->header), "header", 0);
705#endif
706
707   /* skip garbage until 0 bits are coming in */
708   src = squeeze_unsync(bits, src, 40);
709   /* sync on label preamble */
710   src = squeeze_sync(bits, src, 40);
711   LOG_DRIVE((0,"   label  sync bit #%d (@%03d.%02d)\n", src, src / 32, src % 32));
712   src = squeeze_record(bits, src, s->label, sizeof(s->label));
713   src = squeeze_cksum(bits, src, &cksum_label);
714#if   DIABLO_DEBUG
715   dump_record(s->label, 0, sizeof(s->label), "label", 0);
716#endif
717
718   /* skip garbage until 0 bits are coming in */
719   src = squeeze_unsync(bits, src, 40);
720   /* sync on data preamble */
721   src = squeeze_sync(bits, src, 40);
722   LOG_DRIVE((0,"   data   sync bit #%d (@%03d.%02d)\n", src, src / 32, src % 32));
723   src = squeeze_record(bits, src, s->data, sizeof(s->data));
724   src = squeeze_cksum(bits, src, &cksum_data);
725#if   DIABLO_DEBUG
726   dump_record(s->data, 0, sizeof(s->data), "data", 1);
727#endif
728
729   /* TODO: what is the cksum start value for the data record? */
730   cksum_header ^= cksum(s->header, sizeof(s->header), 0521);
731   cksum_label ^= cksum(s->label, sizeof(s->label), 0521);
732   cksum_data ^= cksum(s->data, sizeof(s->data), 0521);
733
734   if (cksum_header || cksum_label || cksum_data) {
735#if   DIABLO_DEBUG
736      LOG_DRIVE((0,"   cksum check - header:%06o label:%06o data:%06o\n", cksum_header, cksum_label, cksum_data));
737#else
738      printf("   cksum check - header:%06o label:%06o data:%06o\n", cksum_header, cksum_label, cksum_data);
739#endif
740   }
741   global_free(m_bits[m_page]);
742   m_bits[m_page] = 0;
743}
744
745/**
746 * @brief return number of bitclk edges for a sector
747 * @return number of bitclk edges for a sector
748 */
749int diablo_hd_device::bits_per_sector() const
750{
751   return m_diablo31 ? DIABLO31_SECTOR_WORDS * 32 : DIABLO44_SECTOR_WORDS * 32;
752}
753
754/**
755 * @brief return a pointer to a drive's description
756 * @return a pointer to the string description
757 */
758const char* diablo_hd_device::description() const
759{
760   return m_description;
761}
762
763/**
764 * @brief return the number of a drive unit
765 * @return the unit number
766 */
767int diablo_hd_device::unit() const
768{
769   return m_unit;
770}
771
772/**
773 * @brief return the time for a full rotation
774 * @return the time for a full track rotation in atto seconds
775 */
776attotime diablo_hd_device::rotation_time() const
777{
778   return m_rotation_time;
779}
780
781/**
782 * @brief return the time for a sector
783 * @return the time for a sector in atto seconds
784 */
785attotime diablo_hd_device::sector_time() const
786{
787   return m_sector_time;
788}
789
790/**
791 * @brief return the time for a data bit
792 * @return the time in atto seconds per bit clock
793 */
794attotime diablo_hd_device::bit_time() const
795{
796   return m_bit_time;
797}
798
799/**
800 * @brief return the seek/read/write status of a drive
801 * @return the seek/read/write status for the drive unit (0: active, 1: inactive)
802 */
803int diablo_hd_device::get_seek_read_write_0() const
804{
805   return m_s_r_w_0;
806}
807
808/**
809 * @brief return the ready status of a drive
810 * @return the ready status for the drive unit (0: ready, 1: not ready)
811 */
812int diablo_hd_device::get_ready_0() const
813{
814   return m_ready_0;
815}
816
817/**
818 * @brief return the current sector mark status of a drive
819 *
820 * The sector mark is derived from the offset into the current sector.
821 *
822 * @return the current sector mark for the drive (0:active 1:inactive)
823 */
824int diablo_hd_device::get_sector_mark_0() const
825{
826   /* no sector marks while seeking (?) */
827   if (m_s_r_w_0)
828      return 1;
829
830   /* return the sector mark */
831   return m_sector_mark_0;
832}
833
834/**
835 * @brief return the address acknowledge state
836 * @return the address acknowledge state
837 */
838int diablo_hd_device::get_addx_acknowledge_0() const
839{
840   return m_addx_acknowledge_0;
841}
842
843/**
844 * @brief return the log address interlock state
845 * @return the log address interlock state (0:active 1:inactive)
846 */
847int diablo_hd_device::get_log_addx_interlock_0() const
848{
849   return m_log_addx_interlock_0;
850}
851
852/**
853 * @brief return the seek incomplete state
854 * @return the address acknowledge state (0:active 1:inactive)
855 */
856int diablo_hd_device::get_seek_incomplete_0() const
857{
858   return m_seek_incomplete_0;
859}
860
861/**
862 * @brief return the current cylinder of a drive unit
863 *
864 * Note: the bus lines are active low, thus the XOR with DRIVE_CYLINDER_MASK.
865 *
866 * @return the current cylinder number for the drive
867 */
868int diablo_hd_device::get_cylinder() const
869{
870   return m_cylinder ^ DIABLO_CYLINDER_MASK;
871}
872
873/**
874 * @brief return the current head of a drive unit
875 *
876 * Note: the bus lines are active low, thus the XOR with DRIVE_HEAD_MASK.
877 *
878 * @return the currently selected head for the drive
879 */
880int diablo_hd_device::get_head() const
881{
882   return m_head ^ DIABLO_HEAD_MASK;
883}
884
885/**
886 * @brief return the current sector of a drive unit
887 *
888 * The current sector number is derived from the time since the
889 * most recent track rotation started.
890 *
891 * Note: the bus lines are active low, thus the XOR with DRIVE_SECTOR_MASK.
892 *
893 * @return the current sector for the drive
894 */
895int diablo_hd_device::get_sector() const
896{
897   return m_sector ^ DIABLO_SECTOR_MASK;
898}
899
900/**
901 * @brief return the current page of a drive unit
902 *
903 * The current page number is derived from the cylinder, head,
904 * and sector numbers.
905 *
906 * @return the current page for the drive
907 */
908int diablo_hd_device::get_page() const
909{
910   return m_page;
911}
912
913/**
914 * @brief select a drive unit and head
915 *
916 * @param unit unit number
917 * @param head head number
918 */
919void diablo_hd_device::select(int unit, int head)
920{
921   assert(unit == m_unit);
922   /* this drive is selected */
923   if ((head & DIABLO_HEAD_MASK) != m_head) {
924      m_head = head & DIABLO_HEAD_MASK;
925      printf("select unit:%d head:%d\n", unit, head);
926   }
927
928   if (m_drive) {
929      /* it is ready */
930      m_ready_0 = 0;
931      /* and can take seek/read/write commands */
932      m_s_r_w_0 = 0;
933      /* address acknowledge (?) */
934      m_addx_acknowledge_0 = 0;
935      /* clear log address interlock (?) */
936      m_log_addx_interlock_0 = 1;
937      LOG_DRIVE((1,"   UNIT select %d ready\n", unit));
938   } else {
939      /* it is not ready (?) */
940      m_ready_0 = 1;
941      /* can't take seek/read/write commands (?) */
942      m_s_r_w_0 = 1;
943      /* address acknowledge (?) */
944      m_addx_acknowledge_0 = 0;
945      LOG_DRIVE((1,"   UNIT select %d not ready (no image)\n", unit));
946   }
947   read_sector();
948}
949
950/**
951 * @brief strobe a seek operation
952 *
953 * Seek to the cylinder cylinder, or restore.
954 *
955 * @param unit unit number
956 * @param cylinder cylinder number to seek to
957 * @param restore true, if the drive should restore to cylinder 0
958 * @param strobe current level of the strobe signal (for edge detection)
959 */
960void diablo_hd_device::set_strobe(int cylinder, bool restore, int strobe)
961{
962   int seekto = restore ? 0 : cylinder;
963   if (strobe) {
964      LOG_DRIVE((1,"   STROBE end of interlock\n", seekto));
965      /* deassert the log address interlock */
966      m_log_addx_interlock_0 = 1;
967      return;
968   }
969
970   /* assert the log address interlock */
971   m_log_addx_interlock_0 = 0;
972
973   if (seekto == m_cylinder) {
974      LOG_DRIVE((1,"   STROBE to cylinder %d acknowledge\n", seekto));
975      m_addx_acknowledge_0 = 0;   /* address acknowledge, if cylinder is reached */
976      m_seek_incomplete_0 = 1;   /* reset seek incomplete */
977      return;
978   }
979
980   m_s_r_w_0 = 0;
981
982   if (seekto < m_cylinder) {
983      /* decrement cylinder */
984      m_cylinder--;
985      if (m_cylinder < 0) {
986         m_cylinder = 0;
987         m_log_addx_interlock_0 = 1;   /* deassert the log address interlock */
988         m_seek_incomplete_0 = 1;   /* deassert seek incomplete */
989         m_addx_acknowledge_0 = 0;   /* assert address acknowledge  */
990         LOG_DRIVE((1,"   STROBE to cylinder %d incomplete\n", seekto));
991         return;
992      }
993   } else {
994      /* increment cylinder */
995      m_cylinder++;
996      if (m_cylinder >= DIABLO_CYLINDERS) {
997         m_cylinder = DIABLO_CYLINDERS - 1;
998         m_log_addx_interlock_0 = 1;   /* deassert the log address interlock */
999         m_seek_incomplete_0 = 1;   /* deassert seek incomplete */
1000         m_addx_acknowledge_0 = 0;   /* assert address acknowledge  */
1001         LOG_DRIVE((1,"   STROBE to cylinder %d incomplete\n", seekto));
1002         return;
1003      }
1004   }
1005   LOG_DRIVE((1,"   STROBE to cylinder %d (now %d) - interlock\n", seekto, m_cylinder));
1006
1007   m_addx_acknowledge_0 = 1;   /* deassert address acknowledge  */
1008   m_seek_incomplete_0 = 1;   /* deassert seek incomplete */
1009   read_sector();
1010}
1011
1012/**
1013 * @brief set the drive erase gate
1014 * @param gate value of erase gate
1015 */
1016void diablo_hd_device::set_egate(int gate)
1017{
1018   m_egate_0 = gate & 1;
1019}
1020
1021/**
1022 * @brief set the drive write gate
1023 * @param gate value of write gate
1024 */
1025void diablo_hd_device::set_wrgate(int gate)
1026{
1027   m_wrgate_0 = gate & 1;
1028}
1029
1030/**
1031 * @brief set the drive read gate
1032 * @param gate value of read gate
1033 */
1034void diablo_hd_device::set_rdgate(int gate)
1035{
1036   m_rdgate_0 = gate & 1;
1037}
1038
1039/**
1040 * @brief write the sector relative bit at index
1041 *
1042 * The disk controller writes a combined clock and data pulse to one output
1043 * <PRE>
1044 * Encoding of binary 01011
1045 *
1046 *   clk   data  clk   data  clk   data  clk   data  clk   data
1047 *   0     1     2     3     4     5     6     7     8     9
1048 *   +--+        +--+  +--+  +--+        +--+  +--+  +--+  +--+  +--
1049 *   |  |        |  |  |  |  |  |        |  |  |  |  |  |  |  |  |
1050 * --+  +--------+  +--+  +--+  +--------+  +--+  +--+  +--+  +--+
1051 * </PRE>
1052 *
1053 * @param index relative index of bit/clock into sector
1054 * @param wrdata write data clock or bit
1055 */
1056void diablo_hd_device::wr_data(int index, int wrdata)
1057{
1058   if (m_wrgate_0) {
1059      /* write gate is not asserted (active 0) */
1060      return;
1061   }
1062
1063   /* don't write before or beyond the sector */
1064   if (index < 0 || index >= bits_per_sector())
1065      return;
1066
1067   if (-1 == m_page) {
1068      /* invalid page */
1069      return;
1070   }
1071
1072   UINT32 *bits = expand_sector();
1073   if (-1 == m_wrfirst)
1074      m_wrfirst = index;
1075
1076   LOG_DRIVE((7,"   write #%d %d/%d/%d bit #%d bit:%d\n", unit, m_cylinder, m_head, m_sector, index, wrdata));
1077
1078   if (index < GUARD_ZONE_BITS) {
1079      /* don't write in the guard zone (?) */
1080   } else {
1081      WRBIT(bits,index,wrdata);
1082   }
1083   m_wrlast = index;
1084}
1085
1086/**
1087 * @brief read the sector relative bit at index
1088 *
1089 * Note: this is a gross hack to allow the controller pulling bits
1090 * at its will, rather than clocking them with the drive's RDCLK-
1091 *
1092 * @param index is the sector relative bit index
1093 * @return returns the sector's bit by index
1094 */
1095int diablo_hd_device::rd_data(int index)
1096{
1097   int bit = 0;
1098
1099   if (m_rdgate_0) {
1100      /* read gate is not asserted (active 0) */
1101      return 0;
1102   }
1103
1104   /* don't read before or beyond the sector */
1105   if (index < 0 || index >= bits_per_sector())
1106      return 1;
1107
1108   /* no data while sector mark is low (?) */
1109   if (0 == m_sector_mark_0)
1110      return 1;
1111
1112   if (-1 == m_page) {
1113      /* invalid page */
1114      return 1;
1115   }
1116
1117   UINT32 *bits = expand_sector();
1118
1119   if (-1 == m_rdfirst)
1120      m_rdfirst = index;
1121
1122   RDBIT(bits,index,bit);
1123   LOG_DRIVE((7,"   read #%d %d/%d/%d bit #%d:%d\n", unit, m_cylinder, m_head, m_sector, index, bit));
1124   m_rdlast = index;
1125   return bit;
1126}
1127
1128/**
1129 * @brief get the sector relative clock at index
1130 *
1131 * Note: this is a gross hack to allow the controller pulling bits
1132 * at its will, rather than clocking them with the drive's RDCLK-
1133 *
1134 * @param index is the sector relative bit index
1135 * @return returns the sector's clock bit by index
1136 */
1137int diablo_hd_device::rd_clock(int index)
1138{
1139   int clk = 0;
1140
1141   /* don't read before or beyond the sector */
1142   if (index < 0 || index >= bits_per_sector())
1143      return 1;
1144
1145   /* no clock while sector mark is low (?) */
1146   if (0 == m_sector_mark_0)
1147      return 1;
1148
1149   if (-1 == m_page) {
1150      /* invalid page */
1151      return 1;
1152   }
1153
1154   UINT32 *bits = expand_sector();
1155
1156   if (-1 == m_rdfirst)
1157      m_rdfirst = index;
1158
1159   if (index & 1) {
1160      // clock bits are on even bit positions only
1161      clk = 0;
1162   } else {
1163      RDBIT(bits,index,clk);
1164   }
1165   LOG_DRIVE((7,   "   read #%d %d/%d/%d clk #%d:%d\n", unit, m_cylinder, m_head, m_sector, index, clk));
1166   m_rdlast = index;
1167   return clk ^ 1;
1168}
1169
1170/**
1171 * @brief timer callback that is called once per sector in the rotation
1172 *
1173 * @param id timer id
1174 * @param arg argument supplied to timer_insert (unused)
1175 */
1176void diablo_hd_device::next_sector(void* ptr, int arg)
1177{
1178   (void)ptr;
1179
1180   switch (arg) {
1181   case 0:
1182      m_sector_timer->adjust(m_sector_mark_0_time, 1);
1183      /* deassert sector mark */
1184      sector_mark_1();
1185      break;
1186   case 1:
1187      m_sector_timer->adjust(m_sector_mark_1_time, 2);
1188      /* assert sector mark */
1189      sector_mark_0();
1190      break;
1191   case 2:
1192      /* next sector starting soon now */
1193      m_sector_timer->adjust(m_sector_time - m_sector_mark_0_time, 0);
1194      /* call the sector_callback, if any */
1195      if (m_sector_callback)
1196         (*m_sector_callback)();
1197   }
1198}
1199
1200/**
1201 * @brief timer callback that deasserts the sector mark
1202 *
1203 * @param unit drive unit number
1204 */
1205void diablo_hd_device::sector_mark_1()
1206{
1207   LOG_DRIVE((5, "   %s (unit #%d C/H/S:%d/%d/%d)\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector));
1208   /* set sector mark to 1 */
1209   m_sector_mark_0 = 1;
1210}
1211
1212/**
1213 * @brief timer callback that asserts the sector mark
1214 *
1215 * @param unit drive unit number
1216 */
1217void diablo_hd_device::sector_mark_0()
1218{
1219   LOG_DRIVE((5,"   %s (unit #%d C/H/S:%d/%d/%d)\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector));
1220
1221   /* squeeze previous sector, if it was written to */
1222   squeeze_sector();
1223
1224   m_sector_mark_0 = 0;
1225
1226   /* reset read and write bit locations */
1227   m_rdfirst = -1;
1228   m_rdlast = -1;
1229   m_wrfirst = -1;
1230   m_wrlast = -1;
1231
1232   /* count sectors */
1233   m_sector = (m_sector + 1) % DIABLO_SPT;
1234   read_sector();
1235}
1236
1237void diablo_hd_device::device_start()
1238{
1239   if (m_diablo31) {
1240      snprintf(m_description, sizeof(m_description), "DIABLO31");
1241      m_rotation_time = DIABLO31_ROTATION_TIME;
1242      m_sector_time = DIABLO31_ROTATION_TIME / DIABLO_SPT;
1243      m_sector_mark_0_time = DIABLO31_SECTOR_MARK_PULSE_PRE;
1244      m_sector_mark_1_time = DIABLO31_SECTOR_MARK_PULSE_PRE;
1245      m_bit_time = DIABLO31_BIT_TIME(1);
1246   } else {
1247      snprintf(m_description, sizeof(m_description), "DIABLO44");
1248      m_rotation_time = DIABLO44_ROTATION_TIME;
1249      m_sector_time = DIABLO44_ROTATION_TIME / DIABLO_SPT;
1250      m_sector_mark_0_time = DIABLO44_SECTOR_MARK_PULSE_PRE;
1251      m_sector_mark_1_time = DIABLO44_SECTOR_MARK_PULSE_PRE;
1252      m_bit_time = DIABLO44_BIT_TIME(1);
1253   }
1254
1255   m_sector_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(diablo_hd_device::next_sector),this));
1256   m_sector_timer->adjust(m_sector_time - m_sector_mark_0_time, 0);
1257}
1258
1259void diablo_hd_device::device_reset()
1260{
1261   m_s_r_w_0 = 1;               /* seek/read/write not ready */
1262   m_ready_0 = 1;               /* drive is not ready */
1263   m_sector_mark_0 = 1;         /* sector mark clear */
1264   m_addx_acknowledge_0 = 1;      /* drive address acknowledge is not active */
1265   m_log_addx_interlock_0 = 1;   /* drive log address interlock is not active */
1266   m_seek_incomplete_0 = 1;      /* drive seek incomplete is not active */
1267
1268   /* reset the disk drive's address */
1269   m_cylinder = 0;
1270   m_head = 0;
1271   m_sector = 0;
1272   m_page = -1;
1273
1274   /* disable the gates */
1275   m_egate_0 = 1;
1276   m_wrgate_0 = 1;
1277   m_rdgate_0 = 1;
1278
1279   /* reset read/write first and last indices */
1280   m_wrfirst = -1;
1281   m_wrlast = -1;
1282   m_rdfirst = -1;
1283   m_rdlast = -1;
1284
1285   m_drive = static_cast<harddisk_image_device *>(subdevice("drive"));
1286}
1287
1288MACHINE_CONFIG_FRAGMENT( diablo_drive )
1289   MCFG_HARDDISK_ADD("drive")
1290MACHINE_CONFIG_END
1291
1292machine_config_constructor diablo_hd_device::device_mconfig_additions() const
1293{
1294   return MACHINE_CONFIG_NAME( diablo_drive );
1295}
1296
1297const device_type DIABLO_HD = &device_creator<diablo_hd_device>;
Property changes on: branches/alto2/src/emu/machine/diablo_hd.c
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/emu/machine/diablo_hd.h
r0r26125
1/**********************************************************
2 *   DIABLO31 and DIABLO44 hard drive support
3 *
4 *   Copyright: Juergen Buchmueller <pullmoll@t-online.de>
5 *
6 *   Licenses: MAME, GPLv2
7 **********************************************************/
8
9#if   !defined(_DIABLO_HD_DEVICE_)
10#define _DIABLO_HD_DEVICE_
11
12#include "emu.h"
13#include "imagedev/harddriv.h"
14
15#define   DIABLO_DEBUG   0
16
17#define DIABLO_HD_0 "diablo:0"
18#define DIABLO_HD_1 "diablo:1"
19
20extern const device_type DIABLO_HD;
21
22class diablo_hd_device : public device_t
23{
24public:
25   diablo_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
26
27   int bits_per_sector() const;
28   const char* description() const;
29   int unit() const;
30   attotime rotation_time() const;
31   attotime sector_time() const;
32   attotime bit_time() const;
33
34   int get_seek_read_write_0() const;
35   int get_ready_0() const;
36   int get_sector_mark_0() const;
37   int get_addx_acknowledge_0() const;
38   int get_log_addx_interlock_0() const;
39   int get_seek_incomplete_0() const;
40   int get_cylinder() const;
41   int get_head() const;
42   int get_sector() const;
43   int get_page() const;
44   void select(int unit, int head);
45   void set_strobe(int cylinder, bool restore, int strobe);
46   void set_egate(int gate);
47   void set_wrgate(int gate);
48   void set_rdgate(int gate);
49   void wr_data(int index, int wrdata);
50   int rd_data(int index);
51   int rd_clock(int index);
52
53protected:
54   virtual void    device_start();
55   virtual void    device_reset();
56   virtual machine_config_constructor device_mconfig_additions() const;
57
58private:
59#if   DIABLO_DEBUG
60   int m_log_level;
61   void logprintf(int level, const char* format, ...);
62#   define   LOG_DRIVE(x) logprintf x
63#else
64#   define   LOG_DRIVE(x)
65#endif
66
67   static const int DIABLO_UNIT_MAX = 2;         //!< max number of drive units
68   static const int DIABLO_CYLINDERS = 203;      //!< number of cylinders per drive
69   static const int DIABLO_CYLINDER_MASK = 0777;   //!< bit maks for cylinder number (9 bits)
70   static const int DIABLO_SPT = 12;            //!< number of sectors per track
71   static const int DIABLO_SECTOR_MASK = 017;      //!< bit maks for cylinder number (4 bits)
72   static const int DIABLO_HEADS = 2;            //!< number of heads per drive
73   static const int DIABLO_HEAD_MASK = 1;         //!< bit maks for cylinder number (4 bits)
74   static const int DIABLO_PAGES = 203*2*12;      //!< number of pages per drive
75   //! convert a cylinder/head/sector to a logical block address (page)
76   static inline int DRIVE_PAGE(int c,int h,int s)   { return (c * DIABLO_HEADS + h) * DIABLO_SPT + s; }
77
78   bool m_diablo31;            //!< true, if this is a DIABLO31 drive
79   int m_unit;                  //!< drive unit number (0 or 1)
80   char m_description[32];         //!< description of the drive(s)
81   int m_packs;               //!< number of packs in drive (1 or 2)
82   attotime m_rotation_time;      //!< rotation time in atto seconds
83   attotime m_sector_time;         //!< sector time in atto seconds
84   attotime m_sector_mark_0_time;   //!< sector mark going 0 before sector pulse time
85   attotime m_sector_mark_1_time;   //!< sector mark going 1 after sector pulse time
86   attotime m_bit_time;         //!< bit time in atto seconds
87   int m_s_r_w_0;               //!< drive seek/read/write signal (active 0)
88   int m_ready_0;               //!< drive ready signal (active 0)
89   int m_sector_mark_0;         //!< sector mark (0 if new sector)
90   int m_addx_acknowledge_0;      //!< address acknowledge, i.e. seek successful (active 0)
91   int m_log_addx_interlock_0;      //!< log address interlock, i.e. seek in progress (active 0)
92   int m_seek_incomplete_0;      //!< seek incomplete, i.e. seek in progress (active 0)
93   int m_egate_0;               //!< erase gate
94   int m_wrgate_0;               //!< write gate
95   int m_rdgate_0;               //!< read gate
96   int m_cylinder;               //!< current cylinder number
97   int m_head;                  //!< current head (track) number on cylinder
98   int m_sector;               //!< current sector number in track
99   int m_page;                  //!< current page
100   UINT8* m_image[DIABLO_PAGES];   //!< page raw bytes
101   UINT32* m_bits[DIABLO_PAGES];   //!< page expanded to bits
102   int m_rdfirst;               //!< set to first bit of a sector that is read from
103   int m_rdlast;               //!< set to last bit of a sector that was read from
104   int m_wrfirst;               //!< set to non-zero if a sector is written to
105   int m_wrlast;               //!< set to last bit of a sector that was written to
106   void (*m_sector_callback)();   //!< callback to call at the start of each sector
107   emu_timer* m_sector_timer;      //!< sector timer
108   harddisk_image_device *m_drive;
109
110   void read_sector();            //!< translate C/H/S to a page and read the sector
111   int cksum(UINT8 *src, size_t size, int start);
112   size_t expand_zeroes(UINT32 *bits, size_t dst, size_t size);
113   size_t expand_sync(UINT32 *bits, size_t dst, size_t size);
114   size_t expand_record(UINT32 *bits, size_t dst, UINT8 *field, size_t size);
115   size_t expand_cksum(UINT32 *bits, size_t dst, UINT8 *field, size_t size);
116   UINT32* expand_sector();
117
118   size_t squeeze_sync(UINT32 *bits, size_t src, size_t size);
119   size_t squeeze_unsync(UINT32 *bits, size_t src, size_t size);
120   size_t squeeze_record(UINT32 *bits, size_t src, UINT8 *field, size_t size);
121   size_t squeeze_cksum(UINT32 *bits, size_t src, int *cksum);
122   void squeeze_sector();
123
124   void next_sector(void* ptr, int arg);
125   void sector_mark_1();
126   void sector_mark_0();
127};
128
129#define MCFG_DIABLO_DRIVES_ADD()   \
130   MCFG_DEVICE_ADD(DIABLO_HD_0, DIABLO_HD, 0)   \
131   MCFG_DEVICE_ADD(DIABLO_HD_1, DIABLO_HD, 0)   \
132
133#endif   // !defined(_DIABLO_HD_DEVICE_)
Property changes on: branches/alto2/src/emu/machine/diablo_hd.h
Added: svn:mime-type
   + text/plain
Added: svn:eol-style
   + native
branches/alto2/src/mess/mess.mak
r26124r26125
21012101   $(MESS_DRIVERS)/xerox820.o  \
21022102   $(MESS_DRIVERS)/bigbord2.o  \
21032103   $(MESS_DRIVERS)/alto2.o     \
2104   $(MESS_MACHINE)/diablo_hd.o   \
21052104
21062105$(MESSOBJ)/yamaha.a:            \
21072106   $(MESS_DRIVERS)/ymmu100.o   \
branches/alto2/src/mess/machine/diablo_hd.c
r26124r26125
1/**********************************************************
2 *   DIABLO31 and DIABLO44 hard drive support
3 *
4 *   Copyright: Juergen Buchmueller <pullmoll@t-online.de>
5 *
6 *   Licenses: MAME, GPLv2
7 **********************************************************/
8
9#include "diablo_hd.h"
10
11/**
12 *
13 * Just for completeness' sake:
14 * The mapping of disk controller connector P2 pins to the
15 * Winchester disk drive signals (see drive.h)
16 * <PRE>
17 * Alto Controller     Winchester
18 * P2 signal           disk bus
19 * -----------------------------------------------
20 *  1 GND              D_GROUND
21 *  2 RDCLK'           A_READ_CLOCK
22 *  3 WRDATA'          B_WRITE_DATA_AND_CLOCK
23 *  4 SRWRDY'          F_S_R_W
24 *  5 DISK             L_SELECT_LINE_UNIT_1
25 *  6 CYL(7)'          N_CYL_7
26 *  7 DISK'            R_SELECT_LINE_UNIT_2
27 *  8 CYL(2)'          T_CYL_2
28 *  9 ???              V_SELECT_LINE_UNIT_3
29 * 10 CYL(4)'          X_CYL_4
30 * 11 CYL(0)'          Z_CYL_0
31 * 12 CYL(1)'          BB_CYL_1
32 * 13 CYL(3)'          FF_CYL_3
33 * 14 ???              KK_BIT_2
34 * 15 CYL(8)'          LL_CYL_8
35 * 16 ADRACK'          NN_ADDX_ACKNOWLEDGE
36 * 17 SKINC'           TT_SEEK_INCOMPLETE
37 * 18 LAI'             XX_LOG_ADDX_INTERLOCK
38 * 19 CYL(6)'          RR_CYL_6
39 * 20 RESTOR'          VV_RESTORE
40 * 21 ???              UU_BIT_16
41 * 22 STROBE'          SS_STROBE
42 * 23 ???              MM_BIT_8
43 * 24 ???              KK_BIT_4
44 * 25 ???              HH_WRITE_CHK
45 * 26 WRTGATE'         EE_WRITE_GATE
46 * 27 ???              CC_BIT_SECTOR_ADDX
47 * 28 HEAD'            AA_HEAD_SELECT
48 * 29 ???              Y_INDEX_MARK
49 * 30 SECT(4)'         W_SECTOR_MARK
50 * 31 READY'           U_FILE_READY
51 * 32 ???              S_PSEUDO_SECTOR_MARK
52 * 33 ???              P_WRITE_PROTECT_IND
53 * 34 ???              H_WRITE_PROTECT_INPUT_ATTENTION
54 * 35 ERGATE'          K_ERASE_GATE
55 * 36 ???              M_HIGH_DENSITY
56 * 37 CYL(5)'          J_CYL_5
57 * 38 RDDATA'          C_READ_DATA
58 * 39 RDGATE'          E_READ_GATE
59 * 40 GND              ??
60 * </PRE>
61 */
62
63diablo_hd_device::diablo_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
64   device_t(mconfig, DIABLO_HD, "Diablo Disk", tag, owner, clock, "diablo_hd", __FILE__),
65#if   DIABLO_DEBUG
66   m_log_level(9),
67#endif
68   m_diablo31(true),
69   m_unit(0),
70   m_description(),
71   m_packs(1),
72   m_rotation_time(),
73   m_sector_time(),
74   m_sector_mark_0_time(),
75   m_sector_mark_1_time(),
76   m_bit_time(),
77   m_s_r_w_0(1),
78   m_ready_0(1),
79   m_sector_mark_0(1),
80   m_addx_acknowledge_0(1),
81   m_log_addx_interlock_0(1),
82   m_seek_incomplete_0(1),
83   m_egate_0(1),
84   m_wrgate_0(1),
85   m_rdgate_0(1),
86   m_cylinder(-1),
87   m_head(-1),
88   m_sector(-1),
89   m_page(-1),
90   m_image(),
91   m_bits(),
92   m_rdfirst(-1),
93   m_rdlast(-1),
94   m_wrfirst(-1),
95   m_wrlast(-1),
96   m_sector_callback(0),
97   m_sector_timer(0),
98   m_drive(0)
99{
100}
101
102#if   DIABLO_DEBUG
103void alto2_cpu_device::logprintf(int level, const char* format, ...)
104{
105   if (level > m_log_level)
106      return;
107   va_list ap;
108   va_start(ap, format);
109   debug_console_vprintf(machine(), format, ap);
110   va_end(ap);
111}
112#endif
113
114#define   DIABLO31_ROTATION_TIME attotime::from_msec(39.9999)      //!< DIABLO 31 rotation time is approx. 40ms
115#define   DIABLO31_SECTOR_TIME attotime::from_msec(39.9999/12)   //!< DIABLO 31 sector time
116/**
117 * @brief DIABLO 31 bit clock is 3330kHz ~= 300ns per bit
118 * ~= 133333 bits/track (?)
119 * ~= 11111 bits/sector
120 * ~= 347 words/sector
121 */
122#define   DIABLO31_BIT_TIME(bits) attotime::from_nsec(300*(bits))
123#define   DIABLO31_SECTOR_WORDS 347                        //!< DIABLO 31 possible sector words
124#define   DIABLO31_SECTOR_MARK_PULSE_PRE DIABLO31_BIT_TIME(16)   //!< pulse width of sector mark before the next sector begins
125#define   DIABLO31_SECTOR_MARK_PULSE_POST DIABLO31_BIT_TIME(16)   //!< pulse width of sector mark after the next sector began
126
127#define   DIABLO44_ROTATION_TIME attotime::from_msec(25)         //!< DIABLO 44 rotation time is approx. 25ms
128#define   DIABLO44_SECTOR_TIME   attotime::from_msec(25/12)      //!< DIABLO 44 sector time
129
130/**
131 * @brief DIABLO 44 bit clock is 5000kHz ~= 200ns per bit
132 * ~= 125184 bits/track (?)
133 * ~= 10432 bits/sector
134 * ~= 325 words/sector
135 */
136#define   DIABLO44_BIT_TIME(bits) attotime::from_nsec(200*(bits))
137#define   DIABLO44_SECTOR_WORDS   325                        //!< DIABLO 44 possible sector words
138#define   DIABLO44_SECTOR_MARK_PULSE_PRE DIABLO44_BIT_TIME(16)   //!< pulse width of sector mark before the next sector begins
139#define   DIABLO44_SECTOR_MARK_PULSE_POST DIABLO44_BIT_TIME(16)   //!< pulse width of sector mark after the next sector began
140
141#define   MFROBL         34      //!< from the microcode: disk header preamble is 34 words
142#define   MFRRDL         21      //!< from the microcode: disk header read delay is 21 words
143#define   MIRRDL         4      //!< from the microcode: interrecord read delay is 4 words
144#define   MIROBL         3      //!< from the microcode: disk interrecord preamble is 3 words
145#define   MRPAL         3      //!< from the microcode: disk read postamble length is 3 words
146#define   MWPAL         5      //!< from the microcode: disk write postamble length is 5 words
147
148#define   GUARD_ZONE_BITS   (16*32)   //!< end of the guard zone at the beginning of a sector (wild guess!)
149
150/**
151 * @brief description of the sector layout
152 * <PRE>
153 *
154 *                                   xx.x msec sector mark pulses
155 * -+   +-------------------------------------------------------------------------------+   +--
156 *  |   |                                                                               |   |
157 *  +---+                                                                               +---+
158 *
159 *    |                                                                                   |
160 *
161 *    +------+----+------+-----+------+----+-------+-----+------+----+-------+-----+------+
162 *    | PRE- |SYNC|HEADER|CKSUM| PRE- |SYNC| LABEL |CKSUM| PRE- |SYNC| DATA  |CKSUM| POST |
163 *    |AMBLE1|  1 |      |  1  |AMBLE2|  2 |       |  2  |AMBLE3|  3 |       |  3  |AMBLE |
164 *    +------+----+------+-----+------+----+-------+-----+------+----+-------+-----+------+
165 *
166 *    |                                                                                   |
167 *
168 *    +-----------------------------------------------------------------------------------+
169 *    |                                                                                   |
170 * ---+                                                                                   +----
171 *      FORMAT WRITE GATE FOR INITIALIZING
172 *    |                                                                                   |
173 *
174 *    |                                                    +------------------------------+
175 *                                                         |                              |
176 * ---|----------------------------------------------------+                              +----
177 *      WRITE GATE FOR DATA XFER (*)
178 *    |                                                                                   |
179 *
180 *    |                          +-----------------------+-+------------------------------+
181 *                               |                       | | may be continuous (?)        |
182 * ------------------------------+                       +-+                              +----
183 * ???  WRITE GATE FOR LABEL AND DATA XFER (*)
184 *    |                                                                                   |
185 *
186 *    |   +--------------------+   +---------------------+   +----------------------------+
187 *        |                    |   |                     |   |                            |
188 * -------+                    +---+                     +---+                            +----
189 *      READ GATE FOR INITIALIZING OR DATA XFER (**)
190 *
191 *
192 *  (*) Enable should be delayed 1 byte/word time from last bit of checks sum.
193 *  (**) Read Gate should be enabled half way through the preamble area. This
194 *       ensures reading a zero field for data separator synchronization.
195 *
196 * </PRE>
197 */
198
199#define   DIABLO_PAGENO_WORDS   1      //!< number of words in a page number (this doesn't really belong here)
200#define   DIABLO_HEADER_WORDS   2      //!< number of words in a header (this doesn't really belong here)
201#define   DIABLO_LABEL_WORDS   8      //!< number of words in a label (this doesn't really belong here)
202#define   DIABLO_DATA_WORDS   256      //!< number of data words (this doesn't really belong here)
203#define   DIABLO_CKSUM_WORDS   1      //!< number of words for a checksum (this doesn't really belong here)
204
205/**
206 * @brief format of the cooked disk image sectors, i.e. pure data
207 *
208 * The available images are a multiple of 267 words (534 bytes) per sector,
209 * 1 word page number
210 * 2 words header
211 * 8 words label
212 * 256 words data
213 */
214typedef struct {
215   UINT8 pageno[2*DIABLO_PAGENO_WORDS];   //!< sector page number
216   UINT8 header[2*DIABLO_HEADER_WORDS];   //!< sector header words
217   UINT8 label[2*DIABLO_LABEL_WORDS];      //!< sector label words
218   UINT8 data[2*DIABLO_DATA_WORDS];      //!< sector data words
219}   diablo_sector_t;
220
221/** @brief write a bit into an array of UINT32 */
222static inline size_t WRBIT(UINT32* bits, size_t dst, int bit)
223{
224   if (bit) {
225      bits[(dst)/32] |= 1 << ((dst) % 32);
226   } else {
227      bits[(dst)/32] &= ~(1 << ((dst) % 32));
228   }
229   return ++dst;
230}
231
232/** @brief read a bit from an array of UINT32 */
233static inline size_t RDBIT(UINT32* bits, size_t src, int& bit)
234{
235   bit = (bits[src/32] >> (src % 32)) & 1;
236   return ++src;
237}
238
239/**
240 * @brief calculate the sector from the logical block address and read it
241 *
242 * Modifies drive's page by calculating the logical
243 * block address from cylinder, head, and sector.
244 */
245void diablo_hd_device::read_sector()
246{
247   /* If there's no drive, just reset the page number */
248   if (!m_drive) {
249      m_page = -1;
250      return;
251   }
252   if (m_cylinder < 0 || m_cylinder >= DIABLO_CYLINDERS) {
253      LOG_DRIVE((9,"   DRIVE C/H/S:%d/%d/%d => invalid cylinder\n", m_cylinder, m_head, m_sector));
254      m_page = -1;
255      return;
256   }
257   if (m_head < 0 || m_head >= DIABLO_HEADS) {
258      LOG_DRIVE((9,"   DRIVE C/H/S:%d/%d/%d => invalid head\n", m_cylinder, m_head, m_sector));
259      m_page = -1;
260      return;
261   }
262   if (m_sector < 0 || m_sector >= DIABLO_SPT) {
263      LOG_DRIVE((9,"   DRIVE C/H/S:%d/%d/%d => invalid sector\n", m_cylinder, m_head, m_sector));
264      m_page = -1;
265      return;
266   }
267   /* calculate the new disk relative sector offset */
268   m_page = DRIVE_PAGE(m_cylinder, m_head, m_sector);
269   LOG_DRIVE((9,"   DRIVE C/H/S:%d/%d/%d => page:%d\n", m_cylinder, m_head, m_sector, m_page));
270
271   // already have the sector image?
272   if (m_image[m_page])
273      return;
274
275   hard_disk_file *file = m_drive->get_hard_disk_file();
276   if (!file) {
277      LOG_DRIVE((0,"   no file for unit #%d\n", m_unit));
278      return;
279   }
280
281   /* allocate a sector buffer */
282   m_image[m_page] = global_alloc_array(UINT8, sizeof(diablo_sector_t));
283   if (!hard_disk_read(file, m_page, m_image[m_page])) {
284      LOG_DRIVE((0,"   read failed for #%d page #%d\n", m_unit, m_page));
285      global_free(m_image[m_page]);
286      m_image[m_page] = 0;
287      return;
288   }
289}
290
291/**
292 * @brief compute the checksum of a record
293 *
294 * @param src pointer to a record (header, label, data)
295 * @param size size of the record in bytes
296 * @param start start value for the checksum
297 * @return returns the checksum of the record
298 */
299int diablo_hd_device::cksum(UINT8 *src, size_t size, int start)
300{
301   int sum = start;
302   /* compute XOR of all words */
303   for (size_t offs = 0; offs < size; offs += 2) {
304      int word = src[size - 2 - offs] + 256 * src[size - 2 - offs + 1];
305      sum ^= word;
306   }
307   return sum;
308}
309
310/**
311 * @brief expand a series of clock bits and 0 data bits
312 *
313 * @param bits pointer to the sector bits
314 * @param dst destination offset into bits (bit number)
315 * @param size number of words to write
316 * @return offset to next destination bit
317 */
318size_t diablo_hd_device::expand_zeroes(UINT32 *bits, size_t dst, size_t size)
319{
320   for (size_t offs = 0; offs < 32 * size; offs += 2) {
321      dst = WRBIT(bits, dst, 1);      // write the clock bit
322      dst = WRBIT(bits, dst, 0);      // write the 0 data bit
323   }
324   return dst;
325}
326
327/**
328 * @brief expand a series of 0 words and write a final sync bit
329 *
330 * @param bits pointer to the sector bits
331 * @param dst destination offset into bits (bit number)
332 * @param size number of words to write
333 * @return offset to next destination bit
334 */
335size_t diablo_hd_device::expand_sync(UINT32 *bits, size_t dst, size_t size)
336{
337   for (size_t offs = 0; offs < 32 * size - 2; offs += 2) {
338      dst = WRBIT(bits, dst, 1);      // write the clock bit
339      dst = WRBIT(bits, dst, 0);      // write the 0 data bit
340   }
341   dst = WRBIT(bits, dst, 1);   // write the final clock bit
342   dst = WRBIT(bits, dst, 1);   // write the 1 data bit
343   return dst;
344}
345
346/**
347 * @brief expand a record of words into a array of bits at dst
348 *
349 * @param bits pointer to the sector bits
350 * @param dst destination offset into bits (bit number)
351 * @param field pointer to the record data (bytes)
352 * @param size size of the record in bytes
353 * @return offset to next destination bit
354 */
355size_t diablo_hd_device::expand_record(UINT32 *bits, size_t dst, UINT8 *field, size_t size)
356{
357   for (size_t offs = 0; offs < size; offs += 2) {
358      int word = field[size - 2 - offs] + 256 * field[size - 2 - offs + 1];
359      for (size_t bit = 0; bit < 16; bit++) {
360         dst = WRBIT(bits, dst, 1);               // write the clock bit
361         dst = WRBIT(bits, dst, (word >> 15) & 1);   // write the data bit
362         word <<= 1;
363      }
364   }
365   return dst;
366}
367
368/**
369 * @brief Expand a record's checksum word to 32 bits
370 *
371 * @param bits pointer to the sector bits
372 * @param dst destination offset into bits (bit number)
373 * @param field pointer to the record data (bytes)
374 * @param size size of the record in bytes
375 * @return offset to next destination bit
376 */
377size_t diablo_hd_device::expand_cksum(UINT32 *bits, size_t dst, UINT8 *field, size_t size)
378{
379   int word = cksum(field, size, 0521);
380   for (size_t bit = 0; bit < 32; bit += 2) {
381      dst = WRBIT(bits, dst, 1);            // write the clock bit
382      dst = WRBIT(bits, dst, (word >> 15) & 1);   // write the data bit
383      word <<= 1;
384   }
385   return dst;
386}
387
388/**
389 * @brief Expand a sector into an array of clock and data bits
390 *
391 * @param page page number (0 to DRIVE_PAGES-1)
392 */
393UINT32* diablo_hd_device::expand_sector()
394{
395   size_t dst;
396
397   /* already expanded this sector? */
398   if (m_bits[m_page])
399      return m_bits[m_page];
400
401   /* allocate a sector buffer */
402   if (!m_image[m_page]) {
403      LOG_DRIVE((0,"   no image for #%d page #%d\n", m_unit, m_page));
404      return NULL;
405   }
406   diablo_sector_t *s = reinterpret_cast<diablo_sector_t *>(m_image[m_page]);
407
408   /* allocate a bits image */
409   UINT32 *bits = reinterpret_cast<UINT32 *>(global_alloc_array(UINT32, 400));
410
411   if (m_diablo31) {
412      /* write sync bit after 31 words - 1 bit */
413      dst = expand_sync(bits, 0, 31);
414      dst = expand_record(bits, dst, s->header, sizeof(s->header));
415      dst = expand_cksum(bits, dst, s->header, sizeof(s->header));
416
417      /* write sync bit after 2 * 5 + 1 words - 1 bit */
418      dst = expand_sync(bits, dst, 2 * MWPAL);
419      dst = expand_record(bits, dst, s->label, sizeof(s->label));
420      dst = expand_cksum(bits, dst, s->label, sizeof(s->label));
421
422      /* write sync bit after 2 * 5 + 1 words - 1 bit */
423      dst = expand_sync(bits, dst, 2 * MWPAL);
424      dst = expand_record(bits, dst, s->data, sizeof(s->data));
425      dst = expand_cksum(bits, dst, s->data, sizeof(s->data));
426
427      /* fill MWPAL words of clock and 0 data bits */
428      dst = expand_zeroes(bits, dst, MWPAL);
429   } else {
430      /* write sync bit after 31 words - 1 bit */
431      dst = expand_sync(bits, 0, 31);
432      dst = expand_record(bits, dst, s->header, sizeof(s->header));
433      dst = expand_cksum(bits, dst, s->header, sizeof(s->header));
434
435      /* write sync bit after 2 * 5 words - 1 bit */
436      dst = expand_sync(bits, dst, 2 * MWPAL);
437      dst = expand_record(bits, dst, s->label, sizeof(s->label));
438      dst = expand_cksum(bits, dst, s->label, sizeof(s->label));
439
440      /* write sync bit after 2 * 5 words - 1 bit */
441      dst = expand_sync(bits, dst, 2 * MWPAL);
442      dst = expand_record(bits, dst, s->data, sizeof(s->data));
443      dst = expand_cksum(bits, dst, s->data, sizeof(s->data));
444
445      /* fill MWPAL words of clock and 0 data bits */
446      dst = expand_zeroes(bits, dst, MWPAL);
447   }
448   m_bits[m_page] = bits;
449
450   LOG_DRIVE((0,"   BITS #%d: %03d/%d/%02d #%-5d bits (@%03d.%02d)\n",
451      m_unit, m_cylinder, m_head, m_sector,
452      dst, dst / 32, dst % 32));
453
454   return bits;
455}
456
457#if   DIABLO_DEBUG
458void diablo_hd_device::drive_dump_ascii(UINT8 *src, size_t size)
459{
460   size_t offs;
461   LOG_DRIVE((0," ["));
462   for (offs = 0; offs < size; offs++) {
463      char ch = (char)src[offs ^ 1];
464      LOG_DRIVE((0, "%c", ch < 32 || ch > 126 ? '.' : ch));
465   }
466   LOG_DRIVE((0,"]\n"));
467}
468
469
470/**
471 * @brief Dump a record's contents
472 *
473 * @param src pointer to a record (header, label, data)
474 * @param size size of the record in bytes
475 * @param name name to print before the dump
476 */
477size_t diablo_hd_device::dump_record(UINT8 *src, size_t addr, size_t size, const char *name, int cr)
478{
479   size_t offs;
480   LOG_DRIVE((0,"%s:", name));
481   for (offs = 0; offs < size; offs += 2) {
482      int word = src[offs] + 256 * src[offs + 1];
483      if (offs % 16) {
484         LOG_DRIVE((0," %06o", word));
485      } else {
486         if (offs > 0)
487            drive_dump_ascii(&src[offs-16], 16);
488         LOG_DRIVE((0,"\t%05o: %06o", (addr + offs) / 2, word));
489      }
490   }
491   if (offs % 16) {
492      drive_dump_ascii(&src[offs - (offs % 16)], offs % 16);
493   } else {
494      drive_dump_ascii(&src[offs-16], 16);
495   }
496   if (cr) {
497      LOG_DRIVE((0,"\n"));
498   }
499   return size;
500}
501#endif
502
503/**
504 * @brief find a sync bit in an array of clock and data bits
505 *
506 * @param bits pointer to the sector's bits
507 * @param src source offset into bits (bit number)
508 * @param size number of words to scan for a sync word
509 * @return next source offset for reading
510 */
511size_t diablo_hd_device::squeeze_sync(UINT32 *bits, size_t src, size_t size)
512{
513   UINT32 accu = 0;
514   /* hunt for the first 0x0001 word */
515   for (size_t bitcount = 0, offs = 0; offs < size; /* */) {
516      /*
517       * accumulate clock and data bits until we are
518       * on the clock bit boundary
519       */
520      int bit;
521      src = RDBIT(bits,src,bit);
522      accu = (accu << 1) | bit;
523      /*
524       * look for 15 alternating clocks and 0-bits
525       * and the 16th clock with a 1-bit
526       */
527      if (accu == 0xaaaaaaab)
528         return src;
529      if (++bitcount == 32) {
530         bitcount = 0;
531         offs++;
532      }
533   }
534   /* return if no sync found within size*32 clock and data bits */
535   LOG_DRIVE((0,"   no sync within %d words\n", size));
536   return src;
537}
538
539/**
540 * @brief find a 16 x 0 bits sequence in an array of clock and data bits
541 *
542 * @param bits pointer to the sector's bits
543 * @param src source offset into bits (bit number)
544 * @param size number of words to scan for a sync word
545 * @return next source offset for reading
546 */
547size_t diablo_hd_device::squeeze_unsync(UINT32 *bits, size_t src, size_t size)
548{
549   UINT32 accu = 0;
550   /* hunt for the first 0 word (16 x 0 bits) */
551   for (size_t bitcount = 0, offs = 0; offs < size; /* */) {
552      /*
553       * accumulate clock and data bits until we are
554       * on the clock bit boundary
555       */
556      int bit;
557      src = RDBIT(bits,src,bit);
558      accu = (accu << 1) | bit;
559      /*
560       * look for 16 alternating clocks and 0 data bits
561       */
562      if (accu == 0xaaaaaaaa)
563         return src;
564      if (++bitcount == 32) {
565         bitcount = 0;
566         offs++;
567      }
568   }
569   /* return if no sync found within size*32 clock and data bits */
570   LOG_DRIVE((0,"   no unsync within %d words\n", size));
571   return src;
572}
573
574/**
575 * @brief squeeze an array of clock and data bits into a sector's record
576 *
577 * @param bits pointer to the sector's bits
578 * @param src source offset into bits (bit number)
579 * @param field pointer to the record data (bytes)
580 * @param size size of the record in bytes
581 * @return next source offset for reading
582 */
583size_t diablo_hd_device::squeeze_record(UINT32 *bits, size_t src, UINT8 *field, size_t size)
584{
585   UINT32 accu = 0;
586   for (size_t bitcount = 0, offs = 0; offs < size; /* */) {
587      int bit;
588      src = RDBIT(bits,src,bit);      // skip clock
589      assert(bit == 1);
590      src = RDBIT(bits,src,bit);      // get data bit
591      accu = (accu << 1) | bit;
592      bitcount += 2;
593      if (bitcount == 32) {
594         /* collected a word */
595         field[size - 2 - offs + 0] = accu % 256;
596         field[size - 2 - offs + 1] = accu / 256;
597         offs += 2;
598         bitcount = 0;
599      }
600   }
601   return src;
602}
603
604/**
605 * @brief squeeze an array of 32 clock and data bits into a checksum word
606 *
607 * @param bits pointer to the sector's bits
608 * @param src source offset into bits (bit number)
609 * @param cksum pointer to an int to receive the checksum word
610 * @return next source offset for reading
611 */
612size_t diablo_hd_device::squeeze_cksum(UINT32 *bits, size_t src, int *cksum)
613{
614   UINT32 accu = 0;
615
616   for (size_t bitcount = 0; bitcount < 32; bitcount += 2) {
617      int bit;
618      src = RDBIT(bits,src,bit);      // skip clock
619      assert(bit == 1);
620      src = RDBIT(bits,src,bit);      // get data bit
621      accu = (accu << 1) | bit;
622   }
623
624   /* set the cksum to the extracted word */
625   *cksum = accu;
626   return src;
627}
628
629/**
630 * @brief Squeeze a array of clock and data bits into a sector's data
631 */
632void diablo_hd_device::squeeze_sector()
633{
634   diablo_sector_t *s;
635   size_t src;
636   int cksum_header, cksum_label, cksum_data;
637
638   if (m_rdfirst >= 0) {
639      LOG_DRIVE((0,
640         "   RD #%d %03d/%d/%02d bit#%-5d (@%03d.%02d) ... bit#%-5d (@%03d.%02d)\n",
641         m_unit, m_cylinder, m_head, m_sector,
642         m_rdfirst, m_rdfirst / 32, m_rdfirst % 32,
643         m_rdlast, m_rdlast / 32, m_rdlast % 32));
644   }
645   m_rdfirst = -1;
646   m_rdlast = -1;
647
648   /* not written to, just drop it now */
649   if (m_wrfirst < 0) {
650      m_wrfirst = -1;
651      m_wrlast = -1;
652      return;
653   }
654
655   /* did write into the next sector (?) */
656   if (m_wrlast > m_wrfirst && m_wrlast < 256) {
657      m_wrfirst = -1;
658      m_wrlast = -1;
659      return;
660   }
661
662   if (m_wrfirst >= 0) {
663      LOG_DRIVE((0,
664         "   WR #%d %03d/%d/%02d bit#%-5d (@%03d.%02d) ... bit#%-5d (@%03d.%02d)\n",
665         m_unit, m_cylinder, m_head, m_sector,
666         m_wrfirst, m_wrfirst / 32, m_wrfirst % 32,
667         m_wrlast, m_wrlast / 32, m_wrlast % 32));
668   }
669   m_wrfirst = -1;
670   m_wrlast = -1;
671
672   if (m_page < 0 || m_page >= DIABLO_PAGES) {
673      LOG_DRIVE((0,"   no sector for #%d: %d/%d/%d\n", m_unit, m_cylinder, m_head, m_sector));
674      return;
675   }
676
677   if (!m_image[m_page]) {
678      LOG_DRIVE((0,"   no image for #%d: %d/%d/%d\n", m_unit, m_cylinder, m_head, m_sector));
679      return;
680   }
681
682   /* no bits to write? */
683   if (!m_bits[m_page]) {
684      LOG_DRIVE((0,"   no bits for #%d: %d/%d/%d\n", m_unit, m_cylinder, m_head, m_sector));
685      return;
686   }
687   UINT32 *bits = m_bits[m_page];
688
689   /* pointer to sector buffer */
690   s = reinterpret_cast<diablo_sector_t *>(m_image[m_page]);
691
692   /* zap the sector first */
693   memset(s, 0, sizeof(*s));
694
695   src = MFRRDL * 32;
696   /* skip first words and garbage until 0 bits are coming in */
697   src = squeeze_unsync(bits, src, 40);
698   /* sync on header preamble */
699   src = squeeze_sync(bits, src, 40);
700   LOG_DRIVE((0,"   header sync bit #%d (@%03d.%02d)\n", src, src / 32, src % 32));
701   src = squeeze_record(bits, src, s->header, sizeof(s->header));
702   src = squeeze_cksum(bits, src, &cksum_header);
703#if   DIABLO_DEBUG
704   dump_record(s->header, 0, sizeof(s->header), "header", 0);
705#endif
706
707   /* skip garbage until 0 bits are coming in */
708   src = squeeze_unsync(bits, src, 40);
709   /* sync on label preamble */
710   src = squeeze_sync(bits, src, 40);
711   LOG_DRIVE((0,"   label  sync bit #%d (@%03d.%02d)\n", src, src / 32, src % 32));
712   src = squeeze_record(bits, src, s->label, sizeof(s->label));
713   src = squeeze_cksum(bits, src, &cksum_label);
714#if   DIABLO_DEBUG
715   dump_record(s->label, 0, sizeof(s->label), "label", 0);
716#endif
717
718   /* skip garbage until 0 bits are coming in */
719   src = squeeze_unsync(bits, src, 40);
720   /* sync on data preamble */
721   src = squeeze_sync(bits, src, 40);
722   LOG_DRIVE((0,"   data   sync bit #%d (@%03d.%02d)\n", src, src / 32, src % 32));
723   src = squeeze_record(bits, src, s->data, sizeof(s->data));
724   src = squeeze_cksum(bits, src, &cksum_data);
725#if   DIABLO_DEBUG
726   dump_record(s->data, 0, sizeof(s->data), "data", 1);
727#endif
728
729   /* TODO: what is the cksum start value for the data record? */
730   cksum_header ^= cksum(s->header, sizeof(s->header), 0521);
731   cksum_label ^= cksum(s->label, sizeof(s->label), 0521);
732   cksum_data ^= cksum(s->data, sizeof(s->data), 0521);
733
734   if (cksum_header || cksum_label || cksum_data) {
735#if   DIABLO_DEBUG
736      LOG_DRIVE((0,"   cksum check - header:%06o label:%06o data:%06o\n", cksum_header, cksum_label, cksum_data));
737#else
738      printf("   cksum check - header:%06o label:%06o data:%06o\n", cksum_header, cksum_label, cksum_data);
739#endif
740   }
741   global_free(m_bits[m_page]);
742   m_bits[m_page] = 0;
743}
744
745/**
746 * @brief return number of bitclk edges for a sector
747 * @return number of bitclk edges for a sector
748 */
749int diablo_hd_device::bits_per_sector() const
750{
751   return m_diablo31 ? DIABLO31_SECTOR_WORDS * 32 : DIABLO44_SECTOR_WORDS * 32;
752}
753
754/**
755 * @brief return a pointer to a drive's description
756 * @return a pointer to the string description
757 */
758const char* diablo_hd_device::description() const
759{
760   return m_description;
761}
762
763/**
764 * @brief return the number of a drive unit
765 * @return the unit number
766 */
767int diablo_hd_device::unit() const
768{
769   return m_unit;
770}
771
772/**
773 * @brief return the time for a full rotation
774 * @return the time for a full track rotation in atto seconds
775 */
776attotime diablo_hd_device::rotation_time() const
777{
778   return m_rotation_time;
779}
780
781/**
782 * @brief return the time for a sector
783 * @return the time for a sector in atto seconds
784 */
785attotime diablo_hd_device::sector_time() const
786{
787   return m_sector_time;
788}
789
790/**
791 * @brief return the time for a data bit
792 * @return the time in atto seconds per bit clock
793 */
794attotime diablo_hd_device::bit_time() const
795{
796   return m_bit_time;
797}
798
799/**
800 * @brief return the seek/read/write status of a drive
801 * @return the seek/read/write status for the drive unit (0: active, 1: inactive)
802 */
803int diablo_hd_device::get_seek_read_write_0() const
804{
805   return m_s_r_w_0;
806}
807
808/**
809 * @brief return the ready status of a drive
810 * @return the ready status for the drive unit (0: ready, 1: not ready)
811 */
812int diablo_hd_device::get_ready_0() const
813{
814   return m_ready_0;
815}
816
817/**
818 * @brief return the current sector mark status of a drive
819 *
820 * The sector mark is derived from the offset into the current sector.
821 *
822 * @return the current sector mark for the drive (0:active 1:inactive)
823 */
824int diablo_hd_device::get_sector_mark_0() const
825{
826   /* no sector marks while seeking (?) */
827   if (m_s_r_w_0)
828      return 1;
829
830   /* return the sector mark */
831   return m_sector_mark_0;
832}
833
834/**
835 * @brief return the address acknowledge state
836 * @return the address acknowledge state
837 */
838int diablo_hd_device::get_addx_acknowledge_0() const
839{
840   return m_addx_acknowledge_0;
841}
842
843/**
844 * @brief return the log address interlock state
845 * @return the log address interlock state (0:active 1:inactive)
846 */
847int diablo_hd_device::get_log_addx_interlock_0() const
848{
849   return m_log_addx_interlock_0;
850}
851
852/**
853 * @brief return the seek incomplete state
854 * @return the address acknowledge state (0:active 1:inactive)
855 */
856int diablo_hd_device::get_seek_incomplete_0() const
857{
858   return m_seek_incomplete_0;
859}
860
861/**
862 * @brief return the current cylinder of a drive unit
863 *
864 * Note: the bus lines are active low, thus the XOR with DRIVE_CYLINDER_MASK.
865 *
866 * @return the current cylinder number for the drive
867 */
868int diablo_hd_device::get_cylinder() const
869{
870   return m_cylinder ^ DIABLO_CYLINDER_MASK;
871}
872
873/**
874 * @brief return the current head of a drive unit
875 *
876 * Note: the bus lines are active low, thus the XOR with DRIVE_HEAD_MASK.
877 *
878 * @return the currently selected head for the drive
879 */
880int diablo_hd_device::get_head() const
881{
882   return m_head ^ DIABLO_HEAD_MASK;
883}
884
885/**
886 * @brief return the current sector of a drive unit
887 *
888 * The current sector number is derived from the time since the
889 * most recent track rotation started.
890 *
891 * Note: the bus lines are active low, thus the XOR with DRIVE_SECTOR_MASK.
892 *
893 * @return the current sector for the drive
894 */
895int diablo_hd_device::get_sector() const
896{
897   return m_sector ^ DIABLO_SECTOR_MASK;
898}
899
900/**
901 * @brief return the current page of a drive unit
902 *
903 * The current page number is derived from the cylinder, head,
904 * and sector numbers.
905 *
906 * @return the current page for the drive
907 */
908int diablo_hd_device::get_page() const
909{
910   return m_page;
911}
912
913/**
914 * @brief select a drive unit and head
915 *
916 * @param unit unit number
917 * @param head head number
918 */
919void diablo_hd_device::select(int unit, int head)
920{
921   assert(unit == m_unit);
922   /* this drive is selected */
923   if ((head & DIABLO_HEAD_MASK) != m_head) {
924      m_head = head & DIABLO_HEAD_MASK;
925      printf("select unit:%d head:%d\n", unit, head);
926   }
927
928   if (m_drive) {
929      /* it is ready */
930      m_ready_0 = 0;
931      /* and can take seek/read/write commands */
932      m_s_r_w_0 = 0;
933      /* address acknowledge (?) */
934      m_addx_acknowledge_0 = 0;
935      /* clear log address interlock (?) */
936      m_log_addx_interlock_0 = 1;
937      LOG_DRIVE((1,"   UNIT select %d ready\n", unit));
938   } else {
939      /* it is not ready (?) */
940      m_ready_0 = 1;
941      /* can't take seek/read/write commands (?) */
942      m_s_r_w_0 = 1;
943      /* address acknowledge (?) */
944      m_addx_acknowledge_0 = 0;
945      LOG_DRIVE((1,"   UNIT select %d not ready (no image)\n", unit));
946   }
947   read_sector();
948}
949
950/**
951 * @brief strobe a seek operation
952 *
953 * Seek to the cylinder cylinder, or restore.
954 *
955 * @param unit unit number
956 * @param cylinder cylinder number to seek to
957 * @param restore true, if the drive should restore to cylinder 0
958 * @param strobe current level of the strobe signal (for edge detection)
959 */
960void diablo_hd_device::set_strobe(int cylinder, bool restore, int strobe)
961{
962   int seekto = restore ? 0 : cylinder;
963   if (strobe) {
964      LOG_DRIVE((1,"   STROBE end of interlock\n", seekto));
965      /* deassert the log address interlock */
966      m_log_addx_interlock_0 = 1;
967      return;
968   }
969
970   /* assert the log address interlock */
971   m_log_addx_interlock_0 = 0;
972
973   if (seekto == m_cylinder) {
974      LOG_DRIVE((1,"   STROBE to cylinder %d acknowledge\n", seekto));
975      m_addx_acknowledge_0 = 0;   /* address acknowledge, if cylinder is reached */
976      m_seek_incomplete_0 = 1;   /* reset seek incomplete */
977      return;
978   }
979
980   m_s_r_w_0 = 0;
981
982   if (seekto < m_cylinder) {
983      /* decrement cylinder */
984      m_cylinder--;
985      if (m_cylinder < 0) {
986         m_cylinder = 0;
987         m_log_addx_interlock_0 = 1;   /* deassert the log address interlock */
988         m_seek_incomplete_0 = 1;   /* deassert seek incomplete */
989         m_addx_acknowledge_0 = 0;   /* assert address acknowledge  */
990         LOG_DRIVE((1,"   STROBE to cylinder %d incomplete\n", seekto));
991         return;
992      }
993   } else {
994      /* increment cylinder */
995      m_cylinder++;
996      if (m_cylinder >= DIABLO_CYLINDERS) {
997         m_cylinder = DIABLO_CYLINDERS - 1;
998         m_log_addx_interlock_0 = 1;   /* deassert the log address interlock */
999         m_seek_incomplete_0 = 1;   /* deassert seek incomplete */
1000         m_addx_acknowledge_0 = 0;   /* assert address acknowledge  */
1001         LOG_DRIVE((1,"   STROBE to cylinder %d incomplete\n", seekto));
1002         return;
1003      }
1004   }
1005   LOG_DRIVE((1,"   STROBE to cylinder %d (now %d) - interlock\n", seekto, m_cylinder));
1006
1007   m_addx_acknowledge_0 = 1;   /* deassert address acknowledge  */
1008   m_seek_incomplete_0 = 1;   /* deassert seek incomplete */
1009   read_sector();
1010}
1011
1012/**
1013 * @brief set the drive erase gate
1014 * @param gate value of erase gate
1015 */
1016void diablo_hd_device::set_egate(int gate)
1017{
1018   m_egate_0 = gate & 1;
1019}
1020
1021/**
1022 * @brief set the drive write gate
1023 * @param gate value of write gate
1024 */
1025void diablo_hd_device::set_wrgate(int gate)
1026{
1027   m_wrgate_0 = gate & 1;
1028}
1029
1030/**
1031 * @brief set the drive read gate
1032 * @param gate value of read gate
1033 */
1034void diablo_hd_device::set_rdgate(int gate)
1035{
1036   m_rdgate_0 = gate & 1;
1037}
1038
1039/**
1040 * @brief write the sector relative bit at index
1041 *
1042 * The disk controller writes a combined clock and data pulse to one output
1043 * <PRE>
1044 * Encoding of binary 01011
1045 *
1046 *   clk   data  clk   data  clk   data  clk   data  clk   data
1047 *   0     1     2     3     4     5     6     7     8     9
1048 *   +--+        +--+  +--+  +--+        +--+  +--+  +--+  +--+  +--
1049 *   |  |        |  |  |  |  |  |        |  |  |  |  |  |  |  |  |
1050 * --+  +--------+  +--+  +--+  +--------+  +--+  +--+  +--+  +--+
1051 * </PRE>
1052 *
1053 * @param index relative index of bit/clock into sector
1054 * @param wrdata write data clock or bit
1055 */
1056void diablo_hd_device::wr_data(int index, int wrdata)
1057{
1058   if (m_wrgate_0) {
1059      /* write gate is not asserted (active 0) */
1060      return;
1061   }
1062
1063   /* don't write before or beyond the sector */
1064   if (index < 0 || index >= bits_per_sector())
1065      return;
1066
1067   if (-1 == m_page) {
1068      /* invalid page */
1069      return;
1070   }
1071
1072   UINT32 *bits = expand_sector();
1073   if (-1 == m_wrfirst)
1074      m_wrfirst = index;
1075
1076   LOG_DRIVE((7,"   write #%d %d/%d/%d bit #%d bit:%d\n", unit, m_cylinder, m_head, m_sector, index, wrdata));
1077
1078   if (index < GUARD_ZONE_BITS) {
1079      /* don't write in the guard zone (?) */
1080   } else {
1081      WRBIT(bits,index,wrdata);
1082   }
1083   m_wrlast = index;
1084}
1085
1086/**
1087 * @brief read the sector relative bit at index
1088 *
1089 * Note: this is a gross hack to allow the controller pulling bits
1090 * at its will, rather than clocking them with the drive's RDCLK-
1091 *
1092 * @param index is the sector relative bit index
1093 * @return returns the sector's bit by index
1094 */
1095int diablo_hd_device::rd_data(int index)
1096{
1097   int bit = 0;
1098
1099   if (m_rdgate_0) {
1100      /* read gate is not asserted (active 0) */
1101      return 0;
1102   }
1103
1104   /* don't read before or beyond the sector */
1105   if (index < 0 || index >= bits_per_sector())
1106      return 1;
1107
1108   /* no data while sector mark is low (?) */
1109   if (0 == m_sector_mark_0)
1110      return 1;
1111
1112   if (-1 == m_page) {
1113      /* invalid page */
1114      return 1;
1115   }
1116
1117   UINT32 *bits = expand_sector();
1118
1119   if (-1 == m_rdfirst)
1120      m_rdfirst = index;
1121
1122   RDBIT(bits,index,bit);
1123   LOG_DRIVE((7,"   read #%d %d/%d/%d bit #%d:%d\n", unit, m_cylinder, m_head, m_sector, index, bit));
1124   m_rdlast = index;
1125   return bit;
1126}
1127
1128/**
1129 * @brief get the sector relative clock at index
1130 *
1131 * Note: this is a gross hack to allow the controller pulling bits
1132 * at its will, rather than clocking them with the drive's RDCLK-
1133 *
1134 * @param index is the sector relative bit index
1135 * @return returns the sector's clock bit by index
1136 */
1137int diablo_hd_device::rd_clock(int index)
1138{
1139   int clk = 0;
1140
1141   /* don't read before or beyond the sector */
1142   if (index < 0 || index >= bits_per_sector())
1143      return 1;
1144
1145   /* no clock while sector mark is low (?) */
1146   if (0 == m_sector_mark_0)
1147      return 1;
1148
1149   if (-1 == m_page) {
1150      /* invalid page */
1151      return 1;
1152   }
1153
1154   UINT32 *bits = expand_sector();
1155
1156   if (-1 == m_rdfirst)
1157      m_rdfirst = index;
1158
1159   if (index & 1) {
1160      // clock bits are on even bit positions only
1161      clk = 0;
1162   } else {
1163      RDBIT(bits,index,clk);
1164   }
1165   LOG_DRIVE((7,   "   read #%d %d/%d/%d clk #%d:%d\n", unit, m_cylinder, m_head, m_sector, index, clk));
1166   m_rdlast = index;
1167   return clk ^ 1;
1168}
1169
1170/**
1171 * @brief timer callback that is called once per sector in the rotation
1172 *
1173 * @param id timer id
1174 * @param arg argument supplied to timer_insert (unused)
1175 */
1176void diablo_hd_device::next_sector(void* ptr, int arg)
1177{
1178   (void)ptr;
1179
1180   switch (arg) {
1181   case 0:
1182      m_sector_timer->adjust(m_sector_mark_0_time, 1);
1183      /* deassert sector mark */
1184      sector_mark_1();
1185      break;
1186   case 1:
1187      m_sector_timer->adjust(m_sector_mark_1_time, 2);
1188      /* assert sector mark */
1189      sector_mark_0();
1190      break;
1191   case 2:
1192      /* next sector starting soon now */
1193      m_sector_timer->adjust(m_sector_time - m_sector_mark_0_time, 0);
1194      /* call the sector_callback, if any */
1195      if (m_sector_callback)
1196         (*m_sector_callback)();
1197   }
1198}
1199
1200/**
1201 * @brief timer callback that deasserts the sector mark
1202 *
1203 * @param unit drive unit number
1204 */
1205void diablo_hd_device::sector_mark_1()
1206{
1207   LOG_DRIVE((5, "   %s (unit #%d C/H/S:%d/%d/%d)\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector));
1208   /* set sector mark to 1 */
1209   m_sector_mark_0 = 1;
1210}
1211
1212/**
1213 * @brief timer callback that asserts the sector mark
1214 *
1215 * @param unit drive unit number
1216 */
1217void diablo_hd_device::sector_mark_0()
1218{
1219   LOG_DRIVE((5,"   %s (unit #%d C/H/S:%d/%d/%d)\n", __FUNCTION__, m_unit, m_cylinder, m_head, m_sector));
1220
1221   /* squeeze previous sector, if it was written to */
1222   squeeze_sector();
1223
1224   m_sector_mark_0 = 0;
1225
1226   /* reset read and write bit locations */
1227   m_rdfirst = -1;
1228   m_rdlast = -1;
1229   m_wrfirst = -1;
1230   m_wrlast = -1;
1231
1232   /* count sectors */
1233   m_sector = (m_sector + 1) % DIABLO_SPT;
1234   read_sector();
1235}
1236
1237void diablo_hd_device::device_start()
1238{
1239   if (m_diablo31) {
1240      snprintf(m_description, sizeof(m_description), "DIABLO31");
1241      m_rotation_time = DIABLO31_ROTATION_TIME;
1242      m_sector_time = DIABLO31_ROTATION_TIME / DIABLO_SPT;
1243      m_sector_mark_0_time = DIABLO31_SECTOR_MARK_PULSE_PRE;
1244      m_sector_mark_1_time = DIABLO31_SECTOR_MARK_PULSE_PRE;
1245      m_bit_time = DIABLO31_BIT_TIME(1);
1246   } else {
1247      snprintf(m_description, sizeof(m_description), "DIABLO44");
1248      m_rotation_time = DIABLO44_ROTATION_TIME;
1249      m_sector_time = DIABLO44_ROTATION_TIME / DIABLO_SPT;
1250      m_sector_mark_0_time = DIABLO44_SECTOR_MARK_PULSE_PRE;
1251      m_sector_mark_1_time = DIABLO44_SECTOR_MARK_PULSE_PRE;
1252      m_bit_time = DIABLO44_BIT_TIME(1);
1253   }
1254
1255   m_sector_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(diablo_hd_device::next_sector),this));
1256   m_sector_timer->adjust(m_sector_time - m_sector_mark_0_time, 0);
1257}
1258
1259void diablo_hd_device::device_reset()
1260{
1261   m_s_r_w_0 = 1;               /* seek/read/write not ready */
1262   m_ready_0 = 1;               /* drive is not ready */
1263   m_sector_mark_0 = 1;         /* sector mark clear */
1264   m_addx_acknowledge_0 = 1;      /* drive address acknowledge is not active */
1265   m_log_addx_interlock_0 = 1;   /* drive log address interlock is not active */
1266   m_seek_incomplete_0 = 1;      /* drive seek incomplete is not active */
1267
1268   /* reset the disk drive's address */
1269   m_cylinder = 0;
1270   m_head = 0;
1271   m_sector = 0;
1272   m_page = -1;
1273
1274   /* disable the gates */
1275   m_egate_0 = 1;
1276   m_wrgate_0 = 1;
1277   m_rdgate_0 = 1;
1278
1279   /* reset read/write first and last indices */
1280   m_wrfirst = -1;
1281   m_wrlast = -1;
1282   m_rdfirst = -1;
1283   m_rdlast = -1;
1284
1285   m_drive = static_cast<harddisk_image_device *>(subdevice("drive"));
1286}
1287
1288MACHINE_CONFIG_FRAGMENT( diablo_drive )
1289   MCFG_HARDDISK_ADD("drive")
1290MACHINE_CONFIG_END
1291
1292machine_config_constructor diablo_hd_device::device_mconfig_additions() const
1293{
1294   return MACHINE_CONFIG_NAME( diablo_drive );
1295}
1296
1297const device_type DIABLO_HD = &device_creator<diablo_hd_device>;
branches/alto2/src/mess/machine/diablo_hd.h
r26124r26125
1/**********************************************************
2 *   DIABLO31 and DIABLO44 hard drive support
3 *
4 *   Copyright: Juergen Buchmueller <pullmoll@t-online.de>
5 *
6 *   Licenses: MAME, GPLv2
7 **********************************************************/
8
9#if   !defined(_DIABLO_HD_DEVICE_)
10#define _DIABLO_HD_DEVICE_
11
12#include "emu.h"
13#include "imagedev/harddriv.h"
14
15#define   DIABLO_DEBUG   0
16
17#define DIABLO_HD_0 "diablo:0"
18#define DIABLO_HD_1 "diablo:1"
19
20extern const device_type DIABLO_HD;
21
22class diablo_hd_device : public device_t
23{
24public:
25   diablo_hd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
26
27   int bits_per_sector() const;
28   const char* description() const;
29   int unit() const;
30   attotime rotation_time() const;
31   attotime sector_time() const;
32   attotime bit_time() const;
33
34   int get_seek_read_write_0() const;
35   int get_ready_0() const;
36   int get_sector_mark_0() const;
37   int get_addx_acknowledge_0() const;
38   int get_log_addx_interlock_0() const;
39   int get_seek_incomplete_0() const;
40   int get_cylinder() const;
41   int get_head() const;
42   int get_sector() const;
43   int get_page() const;
44   void select(int unit, int head);
45   void set_strobe(int cylinder, bool restore, int strobe);
46   void set_egate(int gate);
47   void set_wrgate(int gate);
48   void set_rdgate(int gate);
49   void wr_data(int index, int wrdata);
50   int rd_data(int index);
51   int rd_clock(int index);
52
53protected:
54   virtual void    device_start();
55   virtual void    device_reset();
56   virtual machine_config_constructor device_mconfig_additions() const;
57
58private:
59#if   DIABLO_DEBUG
60   int m_log_level;
61   void logprintf(int level, const char* format, ...);
62#   define   LOG_DRIVE(x) logprintf x
63#else
64#   define   LOG_DRIVE(x)
65#endif
66
67   static const int DIABLO_UNIT_MAX = 2;         //!< max number of drive units
68   static const int DIABLO_CYLINDERS = 203;      //!< number of cylinders per drive
69   static const int DIABLO_CYLINDER_MASK = 0777;   //!< bit maks for cylinder number (9 bits)
70   static const int DIABLO_SPT = 12;            //!< number of sectors per track
71   static const int DIABLO_SECTOR_MASK = 017;      //!< bit maks for cylinder number (4 bits)
72   static const int DIABLO_HEADS = 2;            //!< number of heads per drive
73   static const int DIABLO_HEAD_MASK = 1;         //!< bit maks for cylinder number (4 bits)
74   static const int DIABLO_PAGES = 203*2*12;      //!< number of pages per drive
75   //! convert a cylinder/head/sector to a logical block address (page)
76   static inline int DRIVE_PAGE(int c,int h,int s)   { return (c * DIABLO_HEADS + h) * DIABLO_SPT + s; }
77
78   bool m_diablo31;            //!< true, if this is a DIABLO31 drive
79   int m_unit;                  //!< drive unit number (0 or 1)
80   char m_description[32];         //!< description of the drive(s)
81   int m_packs;               //!< number of packs in drive (1 or 2)
82   attotime m_rotation_time;      //!< rotation time in atto seconds
83   attotime m_sector_time;         //!< sector time in atto seconds
84   attotime m_sector_mark_0_time;   //!< sector mark going 0 before sector pulse time
85   attotime m_sector_mark_1_time;   //!< sector mark going 1 after sector pulse time
86   attotime m_bit_time;         //!< bit time in atto seconds
87   int m_s_r_w_0;               //!< drive seek/read/write signal (active 0)
88   int m_ready_0;               //!< drive ready signal (active 0)
89   int m_sector_mark_0;         //!< sector mark (0 if new sector)
90   int m_addx_acknowledge_0;      //!< address acknowledge, i.e. seek successful (active 0)
91   int m_log_addx_interlock_0;      //!< log address interlock, i.e. seek in progress (active 0)
92   int m_seek_incomplete_0;      //!< seek incomplete, i.e. seek in progress (active 0)
93   int m_egate_0;               //!< erase gate
94   int m_wrgate_0;               //!< write gate
95   int m_rdgate_0;               //!< read gate
96   int m_cylinder;               //!< current cylinder number
97   int m_head;                  //!< current head (track) number on cylinder
98   int m_sector;               //!< current sector number in track
99   int m_page;                  //!< current page
100   UINT8* m_image[DIABLO_PAGES];   //!< page raw bytes
101   UINT32* m_bits[DIABLO_PAGES];   //!< page expanded to bits
102   int m_rdfirst;               //!< set to first bit of a sector that is read from
103   int m_rdlast;               //!< set to last bit of a sector that was read from
104   int m_wrfirst;               //!< set to non-zero if a sector is written to
105   int m_wrlast;               //!< set to last bit of a sector that was written to
106   void (*m_sector_callback)();   //!< callback to call at the start of each sector
107   emu_timer* m_sector_timer;      //!< sector timer
108   harddisk_image_device *m_drive;
109
110   void read_sector();            //!< translate C/H/S to a page and read the sector
111   int cksum(UINT8 *src, size_t size, int start);
112   size_t expand_zeroes(UINT32 *bits, size_t dst, size_t size);
113   size_t expand_sync(UINT32 *bits, size_t dst, size_t size);
114   size_t expand_record(UINT32 *bits, size_t dst, UINT8 *field, size_t size);
115   size_t expand_cksum(UINT32 *bits, size_t dst, UINT8 *field, size_t size);
116   UINT32* expand_sector();
117
118   size_t squeeze_sync(UINT32 *bits, size_t src, size_t size);
119   size_t squeeze_unsync(UINT32 *bits, size_t src, size_t size);
120   size_t squeeze_record(UINT32 *bits, size_t src, UINT8 *field, size_t size);
121   size_t squeeze_cksum(UINT32 *bits, size_t src, int *cksum);
122   void squeeze_sector();
123
124   void next_sector(void* ptr, int arg);
125   void sector_mark_1();
126   void sector_mark_0();
127};
128
129#define MCFG_DIABLO_DRIVES_ADD()   \
130   MCFG_DEVICE_ADD(DIABLO_HD_0, DIABLO_HD, 0)   \
131   MCFG_DEVICE_ADD(DIABLO_HD_1, DIABLO_HD, 0)   \
132
133#endif   // !defined(_DIABLO_HD_DEVICE_)

Previous 199869 Revisions Next


© 1997-2024 The MAME Team