1 // license:GPL-2.0+
2 // copyright-holders:Raphael Nabet
3 /*
4     990_hd.c: emulation of a generic ti990 hard disk controller, for use with
5     TILINE-based TI990 systems (TI990/10, /12, /12LR, /10A, Business system 300
6     and 300A).
7 
8     This core will emulate the common feature set found in every disk controller.
9     Most controllers support additional features, but are still compatible with
10     the basic feature set.  I have a little documentation on two specific
11     disk controllers (WD900 and WD800/WD800A), but I have not tried to emulate
12     controller-specific features.
13 
14 
15     Long description: see 2234398-9701 and 2306140-9701.
16 
17 
18     Raphael Nabet 2002-2003
19 */
20 
21 #include "emu.h"
22 
23 #include "990_hd.h"
24 
25 #include "harddisk.h"
26 #include "imagedev/harddriv.h"
27 
28 /* Max sector length is bytes.  Generally 256, except for a few older disk
29 units which use 288-byte-long sectors, and SCSI units which generally use
30 standard 512-byte-long sectors. */
31 /* I chose a limit of 512.  No need to use more until someone writes CD-ROMs
32 for TI990. */
33 #define MAX_SECTOR_SIZE 512
34 
35 /* Description of custom format */
36 /* We can use MAME's harddisk.c image format instead. */
37 
38 /* machine-independent big-endian 32-bit integer */
39 struct UINT32BE
40 {
41 	uint8_t bytes[4];
42 };
43 
get_UINT32BE(UINT32BE word)44 static inline uint32_t get_UINT32BE(UINT32BE word)
45 {
46 	return (word.bytes[0] << 24) | (word.bytes[1] << 16) | (word.bytes[2] << 8) | word.bytes[3];
47 }
48 
49 #ifdef UNUSED_FUNCTION
set_UINT32BE(UINT32BE * word,uint32_t data)50 static inline void set_UINT32BE(UINT32BE *word, uint32_t data)
51 {
52 	word->bytes[0] = (data >> 24) & 0xff;
53 	word->bytes[1] = (data >> 16) & 0xff;
54 	word->bytes[2] = (data >> 8) & 0xff;
55 	word->bytes[3] = data & 0xff;
56 }
57 #endif
58 
59 /* disk image header */
60 struct disk_image_header
61 {
62 	UINT32BE cylinders;         /* number of cylinders on hard disk (big-endian) */
63 	UINT32BE heads;             /* number of heads on hard disk (big-endian) */
64 	UINT32BE sectors_per_track; /* number of sectors per track on hard disk (big-endian) */
65 	UINT32BE bytes_per_sector;  /* number of bytes of data per sector on hard disk (big-endian) */
66 };
67 
68 enum
69 {
70 	header_len = sizeof(disk_image_header)
71 };
72 
73 
74 /* masks for individual bits controller registers */
75 enum
76 {
77 	w0_offline          = 0x8000,
78 	w0_not_ready        = 0x4000,
79 	w0_write_protect    = 0x2000,
80 	w0_unsafe           = 0x1000,
81 	w0_end_of_cylinder  = 0x0800,
82 	w0_seek_incomplete  = 0x0400,
83 	/*w0_offset_active  = 0x0200,*/
84 	w0_pack_change      = 0x0100,
85 
86 	w0_attn_lines       = 0x00f0,
87 	w0_attn_mask        = 0x000f,
88 
89 	w1_extended_command = 0xc000,
90 	/*w1_strobe_early       = 0x2000,
91 	w1_strobe_late      = 0x1000,*/
92 	w1_transfer_inhibit = 0x0800,
93 	w1_command          = 0x0700,
94 	w1_offset           = 0x0080,
95 	w1_offset_forward   = 0x0040,
96 	w1_head_address     = 0x003f,
97 
98 	w6_unit0_sel        = 0x0800,
99 	w6_unit1_sel        = 0x0400,
100 	w6_unit2_sel        = 0x0200,
101 	w6_unit3_sel        = 0x0100,
102 
103 	w7_idle             = 0x8000,
104 	w7_complete         = 0x4000,
105 	w7_error            = 0x2000,
106 	w7_int_enable       = 0x1000,
107 	/*w7_lock_out           = 0x0800,*/
108 	w7_retry            = 0x0400,
109 	w7_ecc              = 0x0200,
110 	w7_abnormal_completion  = 0x0100,
111 	w7_memory_error         = 0x0080,
112 	w7_data_error           = 0x0040,
113 	w7_tiline_timeout_err   = 0x0020,
114 	w7_header_err           = 0x0010,
115 	w7_rate_err             = 0x0008,
116 	w7_command_time_out_err = 0x0004,
117 	w7_search_err           = 0x0002,
118 	w7_unit_err             = 0x0001
119 };
120 
121 /* masks for computer-controlled bit in each controller register  */
122 static const uint16_t w_mask[8] =
123 {
124 	0x000f,     /* Controllers should prevent overwriting of w0 status bits, and I know
125 	            that some controllers do so. */
126 	0xffff,
127 	0xffff,
128 	0xffff,
129 	0xffff,
130 	0xffff,
131 	0xffff,
132 	0xf7ff      /* Don't overwrite reserved bits */
133 };
134 
135 
get_id_from_device(device_t * device)136 int ti990_hdc_device::get_id_from_device( device_t *device )
137 {
138 	int id = -1;
139 
140 	if ( ! strcmp( ":harddisk1", device->tag() ) )
141 	{
142 		id = 0;
143 	}
144 	else if ( ! strcmp( ":harddisk2", device->tag() ) )
145 	{
146 		id = 1;
147 	}
148 	else if ( ! strcmp( ":harddisk3", device->tag() ) )
149 	{
150 		id = 2;
151 	}
152 	else if ( ! strcmp( ":harddisk4", device->tag() ) )
153 	{
154 		id = 3;
155 	}
156 	assert( id >= 0 );
157 
158 	return id;
159 }
160 
161 
162 /*
163     Initialize hard disk unit and open a hard disk image
164 */
DEVICE_IMAGE_LOAD_MEMBER(ti990_hdc_device::load_hd)165 DEVICE_IMAGE_LOAD_MEMBER( ti990_hdc_device::load_hd )
166 {
167 	int id = get_id_from_device( &image.device() );
168 	hd_unit_t *d;
169 	hard_disk_file  *hd_file;
170 
171 	d = &m_d[id];
172 	d->img = &image;
173 
174 	hd_file = dynamic_cast<harddisk_image_device *>(&image)->get_hard_disk_file();
175 
176 	if ( hd_file )
177 	{
178 		const hard_disk_info *standard_header;
179 
180 		d->format = format_mame;
181 		d->hd_handle = hd_file;
182 
183 		/* use standard hard disk image header. */
184 		standard_header = hard_disk_get_info(d->hd_handle);
185 
186 		d->cylinders = standard_header->cylinders;
187 		d->heads = standard_header->heads;
188 		d->sectors_per_track = standard_header->sectors;
189 		d->bytes_per_sector = standard_header->sectorbytes;
190 	}
191 	else
192 	{
193 		/* older, custom format */
194 		disk_image_header custom_header;
195 		int bytes_read;
196 
197 		/* set file descriptor */
198 		d->format = format_old;
199 		d->hd_handle = nullptr;
200 
201 		/* use custom image header. */
202 		/* to convert old header-less images to this format, insert a 16-byte
203 		header as follow: 00 00 03 8f  00 00 00 05  00 00 00 21  00 00 01 00 */
204 		d->img->fseek(0, SEEK_SET);
205 		bytes_read = d->img->fread(&custom_header, sizeof(custom_header));
206 		if (bytes_read != sizeof(custom_header))
207 		{
208 			d->format = format_mame;    /* don't care */
209 			d->wp = 1;
210 			d->unsafe = 1;
211 			return image_init_result::FAIL;
212 		}
213 
214 		d->cylinders = get_UINT32BE(custom_header.cylinders);
215 		d->heads = get_UINT32BE(custom_header.heads);
216 		d->sectors_per_track = get_UINT32BE(custom_header.sectors_per_track);
217 		d->bytes_per_sector = get_UINT32BE(custom_header.bytes_per_sector);
218 	}
219 
220 	if (d->bytes_per_sector > MAX_SECTOR_SIZE)
221 	{
222 		d->format = format_mame;
223 		d->hd_handle = nullptr;
224 		d->wp = 1;
225 		d->unsafe = 1;
226 		return image_init_result::FAIL;
227 	}
228 
229 	/* tell whether the image is writable */
230 	d->wp = image.is_readonly();
231 
232 	d->unsafe = 1;
233 	/* set attention line */
234 	m_w[0] |= (0x80 >> id);
235 
236 	return image_init_result::PASS;
237 }
238 
239 /*
240     close a hard disk image
241 */
DEVICE_IMAGE_UNLOAD_MEMBER(ti990_hdc_device::unload_hd)242 DEVICE_IMAGE_UNLOAD_MEMBER( ti990_hdc_device::unload_hd )
243 {
244 	int id = get_id_from_device(&image.device());
245 	hd_unit_t *d;
246 
247 	d = &m_d[id];
248 
249 	d->format = format_mame;    /* don't care */
250 	d->hd_handle = nullptr;
251 	d->wp = 1;
252 	d->unsafe = 1;
253 
254 	/* clear attention line */
255 	m_w[0] &= ~ (0x80 >> id);
256 }
257 
258 /*
259     Return true if a HD image has been loaded
260 */
is_unit_loaded(int unit)261 int ti990_hdc_device::is_unit_loaded(int unit)
262 {
263 	int reply = 0;
264 
265 	switch (m_d[unit].format)
266 	{
267 	case format_mame:
268 		reply = (m_d[unit].hd_handle != nullptr);
269 		break;
270 
271 	case format_old:
272 		reply = (m_d[unit].img->exists() ? 1 : 0);
273 		break;
274 	}
275 
276 	return reply;
277 }
278 
279 /*
280     Parse the disk select lines, and return the corresponding tape unit.
281     (-1 if none)
282 */
cur_disk_unit()283 int ti990_hdc_device::cur_disk_unit()
284 {
285 	int reply;
286 
287 
288 	if (m_w[6] & w6_unit0_sel)
289 		reply = 0;
290 	else if (m_w[6] & w6_unit1_sel)
291 		reply = 1;
292 	else if (m_w[6] & w6_unit2_sel)
293 		reply = 2;
294 	else if (m_w[6] & w6_unit3_sel)
295 		reply = 3;
296 	else
297 		reply = -1;
298 
299 	if (reply >= MAX_DISK_UNIT)
300 		reply = -1;
301 
302 	return reply;
303 }
304 
305 /*
306     Update interrupt state
307 */
update_interrupt()308 void ti990_hdc_device::update_interrupt()
309 {
310 	if (!m_interrupt_callback.isnull())
311 		m_interrupt_callback((m_w[7] & w7_idle)
312 									&& (((m_w[7] & w7_int_enable) && (m_w[7] & (w7_complete | w7_error)))
313 										|| ((m_w[0] & (m_w[0] >> 4)) & w0_attn_mask)));
314 }
315 
316 /*
317     Check that a sector address is valid.
318 
319     Terminate current command and return non-zero if the address is invalid.
320 */
check_sector_address(int unit,unsigned int cylinder,unsigned int head,unsigned int sector)321 int ti990_hdc_device::check_sector_address(int unit, unsigned int cylinder, unsigned int head, unsigned int sector)
322 {
323 	if ((cylinder > m_d[unit].cylinders) || (head > m_d[unit].heads) || (sector > m_d[unit].sectors_per_track))
324 	{   /* invalid address */
325 		if (cylinder > m_d[unit].cylinders)
326 		{
327 			m_w[0] |= w0_seek_incomplete;
328 			m_w[7] |= w7_idle | w7_error | w7_unit_err;
329 		}
330 		else if (head > m_d[unit].heads)
331 		{
332 			m_w[0] |= w0_end_of_cylinder;
333 			m_w[7] |= w7_idle | w7_error | w7_unit_err;
334 		}
335 		else if (sector > m_d[unit].sectors_per_track)
336 			m_w[7] |= w7_idle | w7_error | w7_command_time_out_err;
337 		update_interrupt();
338 		return 1;
339 	}
340 
341 	return 0;
342 }
343 
344 /*
345     Seek to sector whose address is given
346 */
sector_to_lba(int unit,unsigned int cylinder,unsigned int head,unsigned int sector,unsigned int * lba)347 int ti990_hdc_device::sector_to_lba(int unit, unsigned int cylinder, unsigned int head, unsigned int sector, unsigned int *lba)
348 {
349 	if (check_sector_address(unit, cylinder, head, sector))
350 		return 1;
351 
352 	* lba = (cylinder*m_d[unit].heads + head)*m_d[unit].sectors_per_track + sector;
353 
354 	return 0;
355 }
356 
357 /*
358     Read one given sector
359 */
read_sector(int unit,unsigned int lba,void * buffer,unsigned int bytes_to_read)360 int ti990_hdc_device::read_sector(int unit, unsigned int lba, void *buffer, unsigned int bytes_to_read)
361 {
362 	unsigned long byte_position;
363 	unsigned int bytes_read;
364 
365 	switch (m_d[unit].format)
366 	{
367 	case format_mame:
368 		bytes_read = m_d[unit].bytes_per_sector * hard_disk_read(m_d[unit].hd_handle, lba, buffer);
369 		if (bytes_read > bytes_to_read)
370 			bytes_read = bytes_to_read;
371 		break;
372 
373 	case format_old:
374 		byte_position = lba*m_d[unit].bytes_per_sector + header_len;
375 		m_d[unit].img->fseek(byte_position, SEEK_SET);
376 		bytes_read = m_d[unit].img->fread(buffer, bytes_to_read);
377 		break;
378 
379 	default:
380 		bytes_read = 0;
381 		break;
382 	}
383 
384 	return bytes_read;
385 }
386 
387 /*
388     Write one given sector
389 */
write_sector(int unit,unsigned int lba,const void * buffer,unsigned int bytes_to_write)390 int ti990_hdc_device::write_sector(int unit, unsigned int lba, const void *buffer, unsigned int bytes_to_write)
391 {
392 	unsigned long byte_position;
393 	unsigned int bytes_written;
394 
395 	switch (m_d[unit].format)
396 	{
397 	case format_mame:
398 		bytes_written = m_d[unit].bytes_per_sector * hard_disk_write(m_d[unit].hd_handle, lba, buffer);
399 		if (bytes_written > bytes_to_write)
400 			bytes_written = bytes_to_write;
401 		break;
402 
403 	case format_old:
404 		byte_position = lba*m_d[unit].bytes_per_sector + header_len;
405 		m_d[unit].img->fseek(byte_position, SEEK_SET);
406 		bytes_written = m_d[unit].img->fwrite(buffer, bytes_to_write);
407 		break;
408 
409 	default:
410 		bytes_written = 0;
411 		break;
412 	}
413 
414 	return bytes_written;
415 }
416 
417 /*
418     Handle the store registers command: read the drive geometry.
419 */
store_registers()420 void ti990_hdc_device::store_registers()
421 {
422 	int dma_address;
423 	int byte_count;
424 
425 	uint16_t buffer[3];
426 	int i, real_word_count;
427 
428 	int dsk_sel = cur_disk_unit();
429 
430 
431 	if (dsk_sel == -1)
432 	{
433 		/* No idea what to report... */
434 		m_w[7] |= w7_idle | w7_error | w7_abnormal_completion;
435 		update_interrupt();
436 		return;
437 	}
438 	else if (! is_unit_loaded(dsk_sel))
439 	{   /* offline */
440 		m_w[0] |= w0_offline | w0_not_ready;
441 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
442 		update_interrupt();
443 		return;
444 	}
445 
446 	m_d[dsk_sel].unsafe = 0;      /* I think */
447 
448 	dma_address = ((((int) m_w[6]) << 16) | m_w[5]) & 0x1ffffe;
449 	byte_count = m_w[4] & 0xfffe;
450 
451 	/* formatted words per track */
452 	buffer[0] = (m_d[dsk_sel].sectors_per_track*m_d[dsk_sel].bytes_per_sector) >> 1;
453 	/* MSByte: sectors per track; LSByte: bytes of overhead per sector */
454 	buffer[1] = (m_d[dsk_sel].sectors_per_track << 8) | 0;
455 	/* bits 0-4: heads; bits 5-15: cylinders */
456 	buffer[2] = (m_d[dsk_sel].heads << 11) | m_d[dsk_sel].cylinders;
457 
458 	real_word_count = byte_count >> 1;
459 	if (real_word_count > 3)
460 		real_word_count = 3;
461 
462 	/* DMA */
463 	if (! (m_w[1] & w1_transfer_inhibit))
464 		for (i=0; i<real_word_count; i++)
465 		{
466 			m_memory_space->write_word(dma_address, buffer[i]);
467 			dma_address = (dma_address + 2) & 0x1ffffe;
468 		}
469 
470 	m_w[7] |= w7_idle | w7_complete;
471 	update_interrupt();
472 }
473 
474 /*
475     Handle the write format command: format a complete track on disk.
476 
477     The emulation just clears the track data in the disk image.
478 */
write_format()479 void ti990_hdc_device::write_format()
480 {
481 	unsigned int cylinder, head, sector;
482 	unsigned int lba;
483 
484 	uint8_t buffer[MAX_SECTOR_SIZE];
485 	int bytes_written;
486 
487 	int dsk_sel = cur_disk_unit();
488 
489 
490 	if (dsk_sel == -1)
491 	{
492 		/* No idea what to report... */
493 		m_w[7] |= w7_idle | w7_error | w7_abnormal_completion;
494 		update_interrupt();
495 		return;
496 	}
497 	else if (! is_unit_loaded(dsk_sel))
498 	{   /* offline */
499 		m_w[0] |= w0_offline | w0_not_ready;
500 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
501 		update_interrupt();
502 		return;
503 	}
504 	else if (m_d[dsk_sel].unsafe)
505 	{   /* disk in unsafe condition */
506 		m_w[0] |= w0_unsafe | w0_pack_change;
507 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
508 		update_interrupt();
509 		return;
510 	}
511 	else if (m_d[dsk_sel].wp)
512 	{   /* disk write-protected */
513 		m_w[0] |= w0_write_protect;
514 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
515 		update_interrupt();
516 		return;
517 	}
518 
519 	cylinder = m_w[3];
520 	head = m_w[1] & w1_head_address;
521 
522 	if (sector_to_lba(dsk_sel, cylinder, head, 0, &lba))
523 		return;
524 
525 	memset(buffer, 0, m_d[dsk_sel].bytes_per_sector);
526 
527 	for (sector=0; sector<m_d[dsk_sel].sectors_per_track; sector++)
528 	{
529 		bytes_written = write_sector(dsk_sel, lba, buffer, m_d[dsk_sel].bytes_per_sector);
530 
531 		if (bytes_written != m_d[dsk_sel].bytes_per_sector)
532 		{
533 			m_w[0] |= w0_offline | w0_not_ready;
534 			m_w[7] |= w7_idle | w7_error | w7_unit_err;
535 			update_interrupt();
536 			return;
537 		}
538 
539 		lba++;
540 	}
541 
542 	m_w[7] |= w7_idle | w7_complete;
543 	update_interrupt();
544 }
545 
546 /*
547     Handle the read data command: read a variable number of sectors from disk.
548 */
read_data()549 void ti990_hdc_device::read_data()
550 {
551 	int dma_address;
552 	int byte_count;
553 
554 	unsigned int cylinder, head, sector;
555 	unsigned int lba;
556 
557 	uint8_t buffer[MAX_SECTOR_SIZE];
558 	int bytes_to_read;
559 	int bytes_read;
560 	int i;
561 
562 	int dsk_sel = cur_disk_unit();
563 
564 
565 	if (dsk_sel == -1)
566 	{
567 		/* No idea what to report... */
568 		m_w[7] |= w7_idle | w7_error | w7_abnormal_completion;
569 		update_interrupt();
570 		return;
571 	}
572 	else if (! is_unit_loaded(dsk_sel))
573 	{   /* offline */
574 		m_w[0] |= w0_offline | w0_not_ready;
575 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
576 		update_interrupt();
577 		return;
578 	}
579 	else if (m_d[dsk_sel].unsafe)
580 	{   /* disk in unsafe condition */
581 		m_w[0] |= w0_unsafe | w0_pack_change;
582 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
583 		update_interrupt();
584 		return;
585 	}
586 
587 	dma_address = ((((int) m_w[6]) << 16) | m_w[5]) & 0x1ffffe;
588 	byte_count = m_w[4] & 0xfffe;
589 
590 	cylinder = m_w[3];
591 	head = m_w[1] & w1_head_address;
592 	sector = m_w[2] & 0xff;
593 
594 	if (sector_to_lba(dsk_sel, cylinder, head, sector, &lba))
595 		return;
596 
597 	while (byte_count)
598 	{   /* read data sector per sector */
599 		if (cylinder > m_d[dsk_sel].cylinders)
600 		{
601 			m_w[0] |= w0_seek_incomplete;
602 			m_w[7] |= w7_idle | w7_error | w7_unit_err;
603 			update_interrupt();
604 			return;
605 		}
606 
607 		bytes_to_read = (byte_count < m_d[dsk_sel].bytes_per_sector) ? byte_count : m_d[dsk_sel].bytes_per_sector;
608 		bytes_read = read_sector(dsk_sel, lba, buffer, bytes_to_read);
609 
610 		if (bytes_read != bytes_to_read)
611 		{   /* behave as if the controller could not found the sector ID mark */
612 			m_w[7] |= w7_idle | w7_error | w7_command_time_out_err;
613 			update_interrupt();
614 			return;
615 		}
616 
617 		/* DMA */
618 		if (! (m_w[1] & w1_transfer_inhibit))
619 			for (i=0; i<bytes_read; i+=2)
620 			{
621 				m_memory_space->write_word(dma_address, (((int) buffer[i]) << 8) | buffer[i+1]);
622 				dma_address = (dma_address + 2) & 0x1ffffe;
623 			}
624 
625 		byte_count -= bytes_read;
626 
627 		/* update sector address to point to next sector */
628 		lba++;
629 		sector++;
630 		if (sector == m_d[dsk_sel].sectors_per_track)
631 		{
632 			sector = 0;
633 			head++;
634 			if (head == m_d[dsk_sel].heads)
635 			{
636 				head = 0;
637 				cylinder++;
638 			}
639 		}
640 	}
641 
642 	m_w[7] |= w7_idle | w7_complete;
643 	update_interrupt();
644 }
645 
646 /*
647     Handle the write data command: write a variable number of sectors from disk.
648 */
write_data()649 void ti990_hdc_device::write_data()
650 {
651 	int dma_address;
652 	int byte_count;
653 
654 	unsigned int cylinder, head, sector;
655 	unsigned int lba;
656 
657 	uint8_t buffer[MAX_SECTOR_SIZE];
658 	uint16_t word;
659 	int bytes_written;
660 	int i;
661 
662 	int dsk_sel = cur_disk_unit();
663 
664 
665 	if (dsk_sel == -1)
666 	{
667 		/* No idea what to report... */
668 		m_w[7] |= w7_idle | w7_error | w7_abnormal_completion;
669 		update_interrupt();
670 		return;
671 	}
672 	else if (! is_unit_loaded(dsk_sel))
673 	{   /* offline */
674 		m_w[0] |= w0_offline | w0_not_ready;
675 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
676 		update_interrupt();
677 		return;
678 	}
679 	else if (m_d[dsk_sel].unsafe)
680 	{   /* disk in unsafe condition */
681 		m_w[0] |= w0_unsafe | w0_pack_change;
682 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
683 		update_interrupt();
684 		return;
685 	}
686 	else if (m_d[dsk_sel].wp)
687 	{   /* disk write-protected */
688 		m_w[0] |= w0_write_protect;
689 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
690 		update_interrupt();
691 		return;
692 	}
693 
694 	dma_address = ((((int) m_w[6]) << 16) | m_w[5]) & 0x1ffffe;
695 	byte_count = m_w[4] & 0xfffe;
696 
697 	cylinder = m_w[3];
698 	head = m_w[1] & w1_head_address;
699 	sector = m_w[2] & 0xff;
700 
701 	if (sector_to_lba(dsk_sel, cylinder, head, sector, &lba))
702 		return;
703 
704 	while (byte_count > 0)
705 	{   /* write data sector per sector */
706 		if (cylinder > m_d[dsk_sel].cylinders)
707 		{
708 			m_w[0] |= w0_seek_incomplete;
709 			m_w[7] |= w7_idle | w7_error | w7_unit_err;
710 			update_interrupt();
711 			return;
712 		}
713 
714 		/* DMA */
715 		for (i=0; (i<byte_count) && (i<m_d[dsk_sel].bytes_per_sector); i+=2)
716 		{
717 			word = m_memory_space->read_word(dma_address);
718 			buffer[i] = word >> 8;
719 			buffer[i+1] = word & 0xff;
720 
721 			dma_address = (dma_address + 2) & 0x1ffffe;
722 		}
723 		/* fill with 0s if we did not reach sector end */
724 		for (; i<m_d[dsk_sel].bytes_per_sector; i+=2)
725 			buffer[i] = buffer[i+1] = 0;
726 
727 		bytes_written = write_sector(dsk_sel, lba, buffer, m_d[dsk_sel].bytes_per_sector);
728 
729 		if (bytes_written != m_d[dsk_sel].bytes_per_sector)
730 		{
731 			m_w[0] |= w0_offline | w0_not_ready;
732 			m_w[7] |= w7_idle | w7_error | w7_unit_err;
733 			update_interrupt();
734 			return;
735 		}
736 
737 		byte_count -= bytes_written;
738 
739 		/* update sector address to point to next sector */
740 		lba++;
741 		sector++;
742 		if (sector == m_d[dsk_sel].sectors_per_track)
743 		{
744 			sector = 0;
745 			head++;
746 			if (head == m_d[dsk_sel].heads)
747 			{
748 				head = 0;
749 				cylinder++;
750 			}
751 		}
752 	}
753 
754 	m_w[7] |= w7_idle | w7_complete;
755 	update_interrupt();
756 }
757 
758 /*
759     Handle the unformatted read command: read drive geometry information.
760 */
unformatted_read()761 void ti990_hdc_device::unformatted_read()
762 {
763 	int dma_address;
764 	int byte_count;
765 
766 	unsigned int cylinder, head, sector;
767 
768 	uint16_t buffer[3];
769 	int i, real_word_count;
770 
771 	int dsk_sel = cur_disk_unit();
772 
773 
774 	if (dsk_sel == -1)
775 	{
776 		/* No idea what to report... */
777 		m_w[7] |= w7_idle | w7_error | w7_abnormal_completion;
778 		update_interrupt();
779 		return;
780 	}
781 	else if (! is_unit_loaded(dsk_sel))
782 	{   /* offline */
783 		m_w[0] |= w0_offline | w0_not_ready;
784 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
785 		update_interrupt();
786 		return;
787 	}
788 	else if (m_d[dsk_sel].unsafe)
789 	{   /* disk in unsafe condition */
790 		m_w[0] |= w0_unsafe | w0_pack_change;
791 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
792 		update_interrupt();
793 		return;
794 	}
795 
796 	dma_address = ((((int) m_w[6]) << 16) | m_w[5]) & 0x1ffffe;
797 	byte_count = m_w[4] & 0xfffe;
798 
799 	cylinder = m_w[3];
800 	head = m_w[1] & w1_head_address;
801 	sector = m_w[2] & 0xff;
802 
803 	if (check_sector_address(dsk_sel, cylinder, head, sector))
804 		return;
805 
806 	dma_address = ((((int) m_w[6]) << 16) | m_w[5]) & 0x1ffffe;
807 	byte_count = m_w[4] & 0xfffe;
808 
809 	/* bits 0-4: head address; bits 5-15: cylinder address */
810 	buffer[0] = (head << 11) | cylinder;
811 	/* MSByte: sectors per record (1); LSByte: sector address */
812 	buffer[1] = (1 << 8) | sector;
813 	/* formatted words per record */
814 	buffer[2] = m_d[dsk_sel].bytes_per_sector >> 1;
815 
816 	real_word_count = byte_count >> 1;
817 	if (real_word_count > 3)
818 		real_word_count = 3;
819 
820 	/* DMA */
821 	if (! (m_w[1] & w1_transfer_inhibit))
822 		for (i=0; i<real_word_count; i++)
823 		{
824 			m_memory_space->write_word(dma_address, buffer[i]);
825 			dma_address = (dma_address + 2) & 0x1ffffe;
826 		}
827 
828 	m_w[7] |= w7_idle | w7_complete;
829 	update_interrupt();
830 }
831 
832 /*
833     Handle the restore command: return to track 0.
834 */
restore()835 void ti990_hdc_device::restore()
836 {
837 	int dsk_sel = cur_disk_unit();
838 
839 
840 	if (dsk_sel == -1)
841 	{
842 		/* No idea what to report... */
843 		m_w[7] |= w7_idle | w7_error | w7_abnormal_completion;
844 		update_interrupt();
845 		return;
846 	}
847 	else if (! is_unit_loaded(dsk_sel))
848 	{   /* offline */
849 		m_w[0] |= w0_offline | w0_not_ready;
850 		m_w[7] |= w7_idle | w7_error | w7_unit_err;
851 		update_interrupt();
852 		return;
853 	}
854 
855 	m_d[dsk_sel].unsafe = 0;      /* I think */
856 
857 	/*if (seek_to_sector(dsk_sel, 0, 0, 0))
858 	    return;*/
859 
860 	m_w[7] |= w7_idle | w7_complete;
861 	update_interrupt();
862 }
863 
864 /*
865     Parse command code and execute the command.
866 */
execute_command()867 void ti990_hdc_device::execute_command()
868 {
869 	/* hack */
870 	m_w[0] &= 0xff;
871 
872 	if (m_w[1] & w1_extended_command)
873 		logerror("extended commands not supported\n");
874 
875 	switch (/*((m_w[1] & w1_extended_command) >> 11) |*/ ((m_w[1] & w1_command) >> 8))
876 	{
877 	case 0x00: //0b000:
878 		/* store registers */
879 		logerror("store registers\n");
880 		store_registers();
881 		break;
882 	case 0x01: //0b001:
883 		/* write format */
884 		logerror("write format\n");
885 		write_format();
886 		break;
887 	case 0x02: //0b010:
888 		/* read data */
889 		logerror("read data\n");
890 		read_data();
891 		break;
892 	case 0x03: //0b011:
893 		/* write data */
894 		logerror("write data\n");
895 		write_data();
896 		break;
897 	case 0x04: //0b100:
898 		/* unformatted read */
899 		logerror("unformatted read\n");
900 		unformatted_read();
901 		break;
902 	case 0x05: //0b101:
903 		/* unformatted write */
904 		logerror("unformatted write\n");
905 		/* ... */
906 		m_w[7] |= w7_idle | w7_error | w7_abnormal_completion;
907 		update_interrupt();
908 		break;
909 	case 0x06: //0b110:
910 		/* seek */
911 		logerror("seek\n");
912 		/* This command can (almost) safely be ignored */
913 		m_w[7] |= w7_idle | w7_complete;
914 		update_interrupt();
915 		break;
916 	case 0x07: //0b111:
917 		/* restore */
918 		logerror("restore\n");
919 		restore();
920 		break;
921 	}
922 }
923 
924 /*
925     Read one register in TPCS space
926 */
read(offs_t offset)927 uint16_t ti990_hdc_device::read(offs_t offset)
928 {
929 	if (offset < 8)
930 		return m_w[offset];
931 	else
932 		return 0;
933 }
934 
935 /*
936     Write one register in TPCS space.  Execute command if w7_idle is cleared.
937 */
write(offs_t offset,uint16_t data,uint16_t mem_mask)938 void ti990_hdc_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
939 {
940 	if (offset < 8)
941 	{
942 		/* write protect if a command is in progress */
943 		if (m_w[7] & w7_idle)
944 		{
945 			uint16_t old_data = m_w[offset];
946 
947 			/* Only write writable bits AND honor byte accesses (ha!) */
948 			m_w[offset] = (m_w[offset] & ((~w_mask[offset]) | mem_mask)) | (data & w_mask[offset] & ~mem_mask);
949 
950 			if ((offset == 0) || (offset == 7))
951 				update_interrupt();
952 
953 			if ((offset == 7) && (old_data & w7_idle) && ! (data & w7_idle))
954 			{   /* idle has been cleared: start command execution */
955 				execute_command();
956 			}
957 		}
958 	}
959 }
960 
961 
962 DEFINE_DEVICE_TYPE(TI990_HDC, ti990_hdc_device, "ti990_hdc", "Generic TI-990 Hard Disk Controller")
963 
ti990_hdc_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)964 ti990_hdc_device::ti990_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
965 	: device_t(mconfig, TI990_HDC, tag, owner, clock)
966 	, m_memory_space(*this, finder_base::DUMMY_TAG, -1)
967 	, m_interrupt_callback(*this)
968 {
969 }
970 
971 //-------------------------------------------------
972 //  device_start - device-specific startup
973 //-------------------------------------------------
974 
device_start()975 void ti990_hdc_device::device_start()
976 {
977 	int i;
978 
979 	/* initialize harddisk information */
980 	/* attention lines will be set by DEVICE_IMAGE_LOAD */
981 	for (i=0; i<MAX_DISK_UNIT; i++)
982 	{
983 		m_d[i].format = format_mame;
984 		m_d[i].hd_handle = nullptr;
985 		m_d[i].wp = 1;
986 		m_d[i].unsafe = 1;
987 	}
988 	memset(m_w, 0, sizeof(m_w));
989 	m_w[7] = w7_idle;
990 
991 	/* get references to harddisk devices */
992 	m_d[0].img = dynamic_cast<device_image_interface *>(subdevice("harddisk1"));
993 	m_d[1].img = dynamic_cast<device_image_interface *>(subdevice("harddisk2"));
994 	m_d[2].img = dynamic_cast<device_image_interface *>(subdevice("harddisk3"));
995 	m_d[3].img = dynamic_cast<device_image_interface *>(subdevice("harddisk4"));
996 
997 	m_interrupt_callback.resolve_safe();
998 
999 	update_interrupt();
1000 }
1001 
1002 
1003 //-------------------------------------------------
1004 //  device_add_mconfig - add device configuration
1005 //-------------------------------------------------
1006 
device_add_mconfig(machine_config & config)1007 void ti990_hdc_device::device_add_mconfig(machine_config &config)
1008 {
1009 	harddisk_image_device &harddisk1(HARDDISK(config, "harddisk1"));
1010 	harddisk1.set_device_load(FUNC(ti990_hdc_device::load_hd));
1011 	harddisk1.set_device_unload(FUNC(ti990_hdc_device::unload_hd));
1012 
1013 	harddisk_image_device &harddisk2(HARDDISK(config, "harddisk2"));
1014 	harddisk2.set_device_load(FUNC(ti990_hdc_device::load_hd));
1015 	harddisk2.set_device_unload(FUNC(ti990_hdc_device::unload_hd));
1016 
1017 	harddisk_image_device &harddisk3(HARDDISK(config, "harddisk3"));
1018 	harddisk3.set_device_load(FUNC(ti990_hdc_device::load_hd));
1019 	harddisk3.set_device_unload(FUNC(ti990_hdc_device::unload_hd));
1020 
1021 	harddisk_image_device &harddisk4(HARDDISK(config, "harddisk4"));
1022 	harddisk4.set_device_load(FUNC(ti990_hdc_device::load_hd));
1023 	harddisk4.set_device_unload(FUNC(ti990_hdc_device::unload_hd));
1024 }
1025