1 // license:GPL-2.0+
2 // copyright-holders:Raphael Nabet
3 /*
4     990_dk.c: emulation of a TI FD800 'Diablo' floppy disk controller
5     controller, for use with any TI990 system (and possibly any system which
6     implements the CRU bus).
7 
8     This floppy disk controller supports IBM-format 8" SSSD and DSSD floppies.
9 
10     Raphael Nabet 2003
11 
12     Rewritten as class
13     Michael Zapf 2014
14 
15     TODO: Make it work
16 */
17 
18 #include "emu.h"
19 
20 #include "990_dk.h"
21 
22 /* status bits */
23 enum
24 {
25 	status_OP_complete  = 1 << 0,
26 	status_XFER_ready   = 1 << 1,
27 	status_drv_not_ready= 1 << 2,
28 	status_dat_chk_err  = 1 << 3,
29 	status_seek_err     = 1 << 4,
30 	status_invalid_cmd  = 1 << 5,
31 	status_no_addr_mark = 1 << 6,
32 	status_equ_chk_err  = 1 << 7,
33 	status_ID_chk_err   = 1 << 8,
34 	status_ID_not_found = 1 << 9,
35 	status_ctlr_busy    = 1 << 10,
36 	status_write_prot   = 1 << 11,
37 	status_del_sector   = 1 << 12,
38 	status_interrupt    = 1 << 15,
39 
40 	status_unit_shift   = 13
41 };
42 
43 DEFINE_DEVICE_TYPE(TI99X_FD800, fd800_legacy_device, "ti99x_fd800", "TI FD800 Diablo floppy disk controller")
44 
fd800_legacy_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)45 fd800_legacy_device::fd800_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
46 	: device_t(mconfig, TI99X_FD800, tag, owner, clock),
47 	m_recv_buf(0), m_stat_reg(0), m_xmit_buf(0), m_cmd_reg(0), m_interrupt_f_f(0),
48 	m_int_line(*this), m_buf_pos(0), m_buf_mode(), m_unit(0), m_sector(0)
49 {
50 }
51 
set_interrupt_line()52 void fd800_legacy_device::set_interrupt_line()
53 {
54 	if ((m_stat_reg & status_interrupt) && ! m_interrupt_f_f)
55 		m_int_line(ASSERT_LINE);
56 	else
57 		m_int_line(CLEAR_LINE);
58 }
59 
60 
61 #if 0
62 void fd800_legacy_device::unload_proc(device_image_interface &image)
63 {
64 	int unit = floppy_get_drive(&image.device());
65 
66 	m_drv[unit].log_cylinder[0] = m_drv[unit].log_cylinder[1] = -1;
67 }
68 
69 
70 void fd800_machine_init(void (*interrupt_callback)(running_machine &machine, int state))
71 {
72 	int i;
73 
74 	m_machine = &machine;
75 	m_interrupt_callback = interrupt_callback;
76 
77 	m_stat_reg = 0;
78 	m_interrupt_f_f = 1;
79 
80 	m_buf_pos = 0;
81 	m_buf_mode = bm_off;
82 
83 	for (i=0; i<MAX_FLOPPIES; i++)
84 	{
85 		m_drv[i].img = dynamic_cast<device_image_interface *>(floppy_get_device(machine, i));
86 		m_drv[i].phys_cylinder = -1;
87 		m_drv[i].log_cylinder[0] = m_drv[i].log_cylinder[1] = -1;
88 		m_drv[i].seclen = 64;
89 		floppy_install_unload_proc(&m_drv[i].img->device(), unload_proc);
90 	}
91 
92 	set_interrupt_line();
93 }
94 #endif
95 
96 /*
97     Read the first id field that can be found on the floppy disk.
98 
99     unit: floppy drive index
100     head: selected head
101     cylinder_id: cylinder ID read
102     sector_id: sector ID read
103 
104     Return true if an ID was found
105 */
read_id(int unit,int head,int * cylinder_id,int * sector_id)106 int fd800_legacy_device::read_id(int unit, int head, int *cylinder_id, int *sector_id)
107 {
108 	//uint8_t revolution_count;*/
109 	// chrn_id id;
110 
111 	//revolution_count = 0;*/
112 
113 	/*while (revolution_count < 2)*/
114 	/*{*/
115 	/*  if (m_drv[unit].img->floppy_drive_get_next_id(head, &id))
116 	    {
117 	        if (cylinder_id)
118 	            *cylinder_id = id.C;
119 	        if (sector_id)
120 	            *sector_id = id.R;
121 	        return true;
122 	    }
123 	}*/
124 
125 	return false;
126 }
127 
128 /*
129     Find a sector by id.
130 
131     unit: floppy drive index
132     head: selected head
133     sector: sector ID to search
134     data_id: data ID to be used when calling sector read/write functions
135 
136     Return true if the given sector ID was found
137 */
find_sector(int unit,int head,int sector,int * data_id)138 int fd800_legacy_device::find_sector(int unit, int head, int sector, int *data_id)
139 {
140 /*  uint8_t revolution_count;
141     chrn_id id;
142 
143     revolution_count = 0;
144 
145     while (revolution_count < 2)
146     {
147         if (m_drv[unit].img->floppy_drive_get_next_id(head, &id))
148         {
149             // compare id
150             if ((id.R == sector) && (id.N == 0))
151             {
152                 *data_id = id.data_id;
153                 // get ddam status
154                 // w->ddam = id.flags & ID_FLAG_DELETED_DATA;
155                 return true;
156             }
157         }
158     }
159 */
160 	return false;
161 }
162 
163 /*
164     Perform seek command
165 
166     unit: floppy drive index
167     cylinder: track to seek for
168     head: head for which the seek is performed
169 
170     Return false if the seek was successful
171 */
do_seek(int unit,int cylinder,int head)172 int fd800_legacy_device::do_seek(int unit, int cylinder, int head)
173 {
174 /*  int retries;
175 
176     if (cylinder > 76)
177     {
178         m_stat_reg |= status_invalid_cmd;
179         return true;
180     }
181 
182     if (m_drv[unit].img == nullptr || !m_drv[unit].img->exists())
183     {
184         m_stat_reg |= status_drv_not_ready;
185         return true;
186     }
187 
188     if (m_drv[unit].log_cylinder[head] == -1)
189     {
190         if (!read_id(unit, head, &m_drv[unit].log_cylinder[head], nullptr))
191         {
192             m_stat_reg |= status_ID_not_found;
193             return true;
194         }
195     }
196 
197     if (m_drv[unit].log_cylinder[head] == cylinder)
198     {
199 
200         return false;
201     }
202     for (retries=0; retries<10; retries++)
203     {
204         m_drv[unit].img->floppy_drive_seek(cylinder-m_drv[unit].log_cylinder[head]);
205 
206         if (m_drv[unit].phys_cylinder != -1)
207             m_drv[unit].phys_cylinder += cylinder-m_drv[unit].log_cylinder[head];
208 
209         if (!read_id(unit, head, &m_drv[unit].log_cylinder[head], nullptr))
210         {
211             m_drv[unit].log_cylinder[head] = -1;
212             m_stat_reg |= status_ID_not_found;
213             return true;
214         }
215 
216         if (m_drv[unit].log_cylinder[head] == cylinder)
217         {
218 
219             return false;
220         }
221     }
222 
223     m_stat_reg |= status_seek_err;
224     */
225 	return true;
226 }
227 
228 /*
229     Perform restore command
230 
231     unit: floppy drive index
232 
233     Return false if the restore was successful
234 */
do_restore(int unit)235 int fd800_legacy_device::do_restore(int unit)
236 {
237 	int seek_complete = 0;
238 /*  int seek_count = 0;
239 
240     if (!m_drv[unit].img->exists())
241     {
242         m_stat_reg |= status_drv_not_ready;
243         return true;
244     }
245 
246 
247     while (!(seek_complete = !m_drv[unit].img->floppy_tk00_r()) && (seek_count < 76))
248     {
249         m_drv[unit].img->floppy_drive_seek(-1);
250         seek_count++;
251     }
252     if (! seek_complete)
253     {
254         m_drv[unit].phys_cylinder = -1;
255         m_stat_reg |= status_seek_err;
256     }
257     else
258     {
259         m_drv[unit].phys_cylinder = 0;
260 
261     }
262 */
263 	return ! seek_complete;
264 }
265 
266 /*
267     Perform a read operation for one sector
268 */
do_read()269 void fd800_legacy_device::do_read()
270 {
271 /*  int data_id;
272 
273     if ((m_sector == 0) || (m_sector > 26))
274     {
275         m_stat_reg |= status_invalid_cmd;
276         return;
277     }
278 
279     if (!find_sector(m_unit, m_head, m_sector, &data_id))
280     {
281         m_stat_reg |= status_ID_not_found;
282         return;
283     }
284 
285     m_drv[m_unit].img->floppy_drive_read_sector_data(m_head, data_id, m_buf, 128);
286     m_buf_pos = 0;
287     m_buf_mode = bm_read;
288     m_recv_buf = (m_buf[m_buf_pos<<1] << 8) | m_buf[(m_buf_pos<<1)+1];
289 
290     m_stat_reg |= status_XFER_ready;
291     m_stat_reg |= status_OP_complete;
292 */
293 }
294 
295 /*
296     Perform a write operation for one sector
297 */
do_write()298 void fd800_legacy_device::do_write()
299 {
300 /*  int data_id;
301 
302     if (m_drv[m_unit].seclen < 64)
303         memset(m_buf+(m_drv[m_unit].seclen<<1), 0, (64-m_drv[m_unit].seclen)<<1);
304 
305     if (!find_sector(m_unit, m_head, m_sector, &data_id))
306     {
307         m_stat_reg |= status_ID_not_found;
308         return;
309     }
310 
311     m_drv[m_unit].img->floppy_drive_write_sector_data(m_head, data_id, m_buf, 128, m_ddam);
312     m_buf_pos = 0;
313     m_buf_mode = bm_write;
314 
315     m_stat_reg |= status_XFER_ready;
316     m_stat_reg |= status_OP_complete;
317 */
318 }
319 
320 /*
321     Execute a fdc command
322 */
do_cmd()323 void fd800_legacy_device::do_cmd()
324 {
325 /*
326     int unit;
327     int cylinder;
328     int head;
329     int seclen;
330     int sector;
331 
332 
333     if (m_buf_mode != bm_off)
334     {   // All commands in the midst of read or write are interpreted as Stop
335         unit = (m_cmd_reg >> 10) & 3;
336 
337         // reset status
338         m_stat_reg = unit << status_unit_shift;
339 
340         m_buf_pos = 0;
341         m_buf_mode = bm_off;
342 
343         m_stat_reg |= status_OP_complete;
344 
345         m_stat_reg |= status_interrupt;
346         set_interrupt_line();
347 
348         return;
349     }
350 
351     switch (m_cmd_reg >> 12)
352     {
353     case 0:     // select
354                 //    bits 16-25: 0s
355                 //    bits 26-27: unit number (0-3)
356         unit = (m_cmd_reg >> 10) & 3;
357 
358         // reset status
359         m_stat_reg = unit << status_unit_shift;
360 
361         if (!m_drv[unit].img->exists())
362             m_stat_reg |= status_drv_not_ready; // right???
363         else if (m_drv[unit].img->is_readonly())
364             m_stat_reg |= status_write_prot;
365         else
366             m_stat_reg |= status_OP_complete;
367 
368         m_stat_reg |= status_interrupt;
369         set_interrupt_line();
370         break;
371 
372     case 1:     // seek
373                     bits 16-22: cylinder number (0-76)
374                     bits 23-24: 0s
375                     bits 25: head number (1=upper)
376                     bits 26-27: unit number (0-3)
377         unit = (m_cmd_reg >> 10) & 3;
378         head = (m_cmd_reg >> 9) & 1;
379         cylinder = m_cmd_reg & 0x7f;
380 
381         // reset status
382         m_stat_reg = unit << status_unit_shift;
383 
384         if (!do_seek(unit, cylinder, head))
385             m_stat_reg |= status_OP_complete;
386 
387         m_stat_reg |= status_interrupt;
388         set_interrupt_line();
389         break;
390 
391     case 2:     // restore
392                     bits 16-25: 0s
393                     bits 26-27: unit number (0-3)
394         unit = (m_cmd_reg >> 10) & 3;
395 
396         // reset status
397         m_stat_reg = unit << status_unit_shift;
398 
399         if (!do_restore(unit))
400             m_stat_reg |= status_OP_complete;
401 
402         m_stat_reg |= status_interrupt;
403         set_interrupt_line();
404         break;
405 
406     case 3:     // sector length
407                     bits 16-22: sector word count (0-64)
408                     bits 23-25: 0s
409                     bits 26-27: unit number (0-3)
410         unit = (m_cmd_reg >> 10) & 3;
411         seclen = m_cmd_reg & 0x7f;
412 
413         // reset status
414         m_stat_reg = unit << status_unit_shift;
415 
416         if ((seclen > 64) || (seclen == 0))
417         {
418             m_stat_reg |= status_invalid_cmd;
419         }
420         else
421         {
422             m_drv[unit].seclen = seclen;
423             m_stat_reg |= status_OP_complete;
424         }
425 
426         m_stat_reg |= status_interrupt;
427         set_interrupt_line();
428         break;
429 
430     case 4:     // read
431                     bits 16-20: sector number (1-26)
432                     bits 21-23: 0s
433                     bit 24: no sequential sectoring (1=active)
434                     bit 25: head number (1=upper)
435                     bits 26-27: unit number (0-3)
436         unit = (m_cmd_reg >> 10) & 3;
437         head = (m_cmd_reg >> 9) & 1;
438         //non_seq_mode = (m_cmd_reg >> 8) & 1;
439         sector = m_cmd_reg & 0x1f;
440 
441         m_unit = unit;
442         m_head = head;
443         m_sector = sector;
444         //m_non_seq_mode = non_seq_mode;
445 
446         // reset status
447         m_stat_reg = unit << status_unit_shift;
448 
449         do_read();
450 
451         m_stat_reg |= status_interrupt;
452         set_interrupt_line();
453         break;
454 
455     case 5:     // read ID
456                     bits 16-24: 0s
457                     bit 25: head number (1=upper)
458                     bits 26-27: unit number (0-3)
459         unit = (m_cmd_reg >> 10) & 3;
460         head = (m_cmd_reg >> 9) & 1;
461 
462         // reset status
463         m_stat_reg = unit << status_unit_shift;
464 
465         if (!read_id(unit, head, &cylinder, &sector))
466         {
467             m_stat_reg |= status_ID_not_found;
468         }
469         else
470         {
471             m_recv_buf = (cylinder << 8) | sector;
472             m_stat_reg |= status_OP_complete;
473         }
474 
475         m_stat_reg |= status_interrupt;
476         set_interrupt_line();
477         break;
478 
479     case 6:     // read unformatted
480                     bits 16-20: sector number (1-26)
481                     bits 21-24: 0s
482                     bit 25: head number (1=upper)
483                     bits 26-27: unit number (0-3)
484         // ...
485         break;
486 
487     case 7:     // write
488                     bits 16-20: sector number (1-26)
489                     bits 21-24: 0s
490                     bit 25: head number (1=upper)
491                     bits 26-27: unit number (0-3)
492         unit = (m_cmd_reg >> 10) & 3;
493         head = (m_cmd_reg >> 9) & 1;
494         sector = m_cmd_reg & 0x1f;
495 
496         // reset status
497         m_stat_reg = unit << status_unit_shift;
498 
499         if ((m_sector == 0) || (m_sector > 26))
500         {
501             m_stat_reg |= status_invalid_cmd;
502         }
503         else
504         {
505             m_unit = unit;
506             m_head = head;
507             m_sector = sector;
508             m_ddam = 0;
509 
510             m_buf_pos = 0;
511             m_buf_mode = bm_write;
512             m_stat_reg |= status_XFER_ready;
513             m_stat_reg |= status_OP_complete;   // right???
514         }
515 
516         m_stat_reg |= status_interrupt;
517         set_interrupt_line();
518         break;
519 
520     case 8:     // write delete
521                     bits 16-20: sector number (1-26)
522                     bits 21-24: 0s
523                     bit 25: head number (1=upper)
524                     bits 26-27: unit number (0-3)
525         unit = (m_cmd_reg >> 10) & 3;
526         head = (m_cmd_reg >> 9) & 1;
527         sector = m_cmd_reg & 0x1f;
528 
529         // reset status
530         m_stat_reg = unit << status_unit_shift;
531 
532         if ((m_sector == 0) || (m_sector > 26))
533         {
534             m_stat_reg |= status_invalid_cmd;
535         }
536         else
537         {
538             m_unit = unit;
539             m_head = head;
540             m_sector = sector;
541             m_ddam = 1;
542 
543             m_buf_pos = 0;
544             m_buf_mode = bm_write;
545             m_stat_reg |= status_XFER_ready;
546             m_stat_reg |= status_OP_complete;   // right???
547         }
548 
549         m_stat_reg |= status_interrupt;
550         set_interrupt_line();
551         break;
552 
553     case 9:     // format track
554                     bits 16-23: track ID (0-255, normally current cylinder index, or 255 for bad track)
555                     bit 24: verify only (1 - verify, 0 - format & verify)
556                     bit 25: head number (1=upper)
557                     bits 26-27: unit number (0-3)
558         // ...
559         break;
560 
561     case 10:    // load int mask
562                     bit 16: bad mask for interrupt (0 = unmask or enable interrupt)
563                     bits 17-27: 0s
564         m_interrupt_f_f = m_cmd_reg & 1;
565         set_interrupt_line();
566         break;
567 
568     case 11:    // stop
569                     bits 16-25: 0s
570                     bits 26-27: unit number (0-3)
571         unit = (m_cmd_reg >> 10) & 3;
572 
573         // reset status
574         m_stat_reg = unit << status_unit_shift;
575 
576         m_stat_reg |= status_OP_complete;
577 
578         m_stat_reg |= status_interrupt;
579         set_interrupt_line();
580         break;
581 
582     case 12:    // step head
583                     bits 16-22: track number (0-76)
584                     bits 23-25: 0s
585                     bits 26-27: unit number (0-3)
586         unit = (m_cmd_reg >> 10) & 3;
587         cylinder = m_cmd_reg & 0x7f;
588 
589         if (cylinder > 76)
590         {
591             m_stat_reg |= status_invalid_cmd;
592         }
593         else if ((m_drv[unit].phys_cylinder != -1) || (!do_restore(unit)))
594         {
595             m_drv[unit].img->floppy_drive_seek(cylinder-m_drv[unit].phys_cylinder);
596             m_stat_reg |= status_OP_complete;
597         }
598 
599         m_stat_reg |= status_interrupt;
600         set_interrupt_line();
601         break;
602 
603     case 13:    // maintenance commands
604                     bits 16-23: according to extended command code
605                     bits 24-27: extended command code (0-7)
606         switch ((m_cmd_reg >> 8) & 15)
607         {
608         case 0: // reset
609                     bits 16-23: 0s
610             // ...
611             break;
612         case 1: // retry inhibit
613                     bits 16-23: 0s
614             // ...
615             break;
616         case 2: // LED test
617                     bit 16: 1
618                     bits 17-19: 0s
619                     bit 20: LED #2 enable
620                     bit 21: LED #3 enable
621                     bit 22: LED #4 enable
622                     bit 23: enable LEDs
623             // ...
624             break;
625         case 3: // program error (a.k.a. invalid command)
626                     bits 16-23: 0s
627             // ...
628             break;
629         case 4: // memory read
630                     bits 16-20: controller memory address (shifted left by 8 to generate 9900 address)
631                     bits 21-23: 0s
632             // ...
633             break;
634         case 5: // RAM load
635                     bit 16: 0
636                     bits 17-23: RAM offset (shifted left by 1 and offset by >1800 to generate 9900 address)
637             // ...
638             break;
639         case 6: // RAM run
640                     bit 16: 0
641                     bits 17-23: RAM offset (shifted left by 1 and offset by >1800 to generate 9900 address)
642             // ...
643             break;
644         case 7: // power up simulation
645                     bits 16-23: 0s
646             // ...
647             break;
648         }
649         // ...
650         break;
651 
652     case 14:    // IPL
653                     bits 16-22: track number (0-76)
654                     bit 23: 0
655                     bit 24: no sequential sectoring (1=active)
656                     bit 25: head number (1=upper)
657                     bits 26-27: unit number (0-3)
658         unit = (m_cmd_reg >> 10) & 3;
659         head = (m_cmd_reg >> 9) & 1;
660         //non_seq_mode = (m_cmd_reg >> 8) & 1;
661         cylinder = m_cmd_reg & 0x7f;
662 
663         if (!do_seek(unit, cylinder, head))
664         {
665             m_unit = unit;
666             m_head = head;
667             m_sector = 1;
668             //m_non_seq_mode = non_seq_mode;
669 
670             do_read();
671         }
672 
673         m_stat_reg |= status_interrupt;
674         set_interrupt_line();
675         break;
676 
677     case 15:    // Clear Status port
678                     bits 16-27: 0s
679         m_stat_reg = 0;
680         set_interrupt_line();
681         break;
682     }
683     */
684 }
685 
686 /*
687     read one CRU bit
688 
689     0-15: receive buffer
690     16-31: status:
691         16: OP complete (1 -> complete???)
692         17: Xfer ready (XFER) (1 -> ready???)
693         18: drive not ready
694         19: data check error
695         20: seek error/??????
696         21 invalid command/??????
697         22: no address mark found/??????
698         23: equipment check error/??????
699         24: ID check error
700         25: ID not found
701         26: Controller busy (CTLBSY) (0 -> controller is ready)
702         27: write protect
703         28: deleted sector detected
704         29: unit LSB
705         30: unit MSB
706         31: Interrupt (CBUSY???) (1 -> controller is ready)
707 */
cru_r(offs_t offset)708 uint8_t fd800_legacy_device::cru_r(offs_t offset)
709 {
710 	int reply = 0;
711 
712 	offset &= 31;
713 	if (offset < 16)
714 	{
715 		// receive buffer
716 		reply = BIT(m_recv_buf, offset);
717 	}
718 	else
719 	{
720 		// status register
721 		reply = BIT(m_stat_reg, offset - 16);
722 	}
723 
724 	return reply;
725 }
726 
727 /*
728     write one CRU bit
729 
730     0-15: controller data word (transmit buffer)
731     16-31: controller command word (command register)
732     16-23: parameter value
733     24: flag bit/extended command code
734     25: head select/extended command code
735     26: FD unit number LSB/extended command code
736     27: FD unit number MSB/extended command code
737     28-31: command code
738 */
cru_w(offs_t offset,uint8_t data)739 void fd800_legacy_device::cru_w(offs_t offset, uint8_t data)
740 {
741 	switch (offset)
742 	{
743 	case 0:
744 	case 1:
745 	case 2:
746 	case 3:
747 	case 4:
748 	case 5:
749 	case 6:
750 	case 7:
751 	case 8:
752 	case 9:
753 	case 10:
754 	case 11:
755 	case 12:
756 	case 13:
757 	case 14:
758 	case 15:
759 		// transmit buffer
760 		if (data)
761 			m_xmit_buf |= 1 << offset;
762 		else
763 			m_xmit_buf &= ~(1 << offset);
764 		if (offset == 15)
765 		{
766 			switch (m_buf_mode)
767 			{
768 			case bm_off:
769 				break;
770 			case bm_read:
771 				m_buf_pos++;
772 				if (m_buf_pos == m_drv[m_unit].seclen)
773 				{   // end of sector
774 					if (m_sector == 26)
775 					{   // end of track -> end command (right???)
776 						m_stat_reg &= ~status_XFER_ready;
777 						m_stat_reg |= status_OP_complete;
778 						m_stat_reg |= status_interrupt;
779 						m_buf_mode = bm_off;
780 						set_interrupt_line();
781 					}
782 					else
783 					{   // read next sector
784 						m_sector++;
785 						m_stat_reg &= ~status_XFER_ready | status_OP_complete | status_interrupt;
786 						do_read();
787 						m_stat_reg |= status_interrupt;
788 						set_interrupt_line();
789 					}
790 				}
791 				else
792 					m_recv_buf = (m_buf[m_buf_pos<<1] << 8) | m_buf[(m_buf_pos<<1)+1];
793 				break;
794 
795 			case bm_write:
796 				m_buf[m_buf_pos<<1] = m_xmit_buf >> 8;
797 				m_buf[(m_buf_pos<<1)+1] = m_xmit_buf & 0xff;
798 				m_buf_pos++;
799 				if (m_buf_pos == m_drv[m_unit].seclen)
800 				{   // end of sector
801 					do_write();
802 					if (m_sector == 26)
803 					{
804 						// end of track -> end command (right???)
805 						m_stat_reg &= ~status_XFER_ready;
806 						m_stat_reg |= status_OP_complete;
807 						m_stat_reg |= status_interrupt;
808 						m_buf_mode = bm_off;
809 						set_interrupt_line();
810 					}
811 					else
812 					{   // increment to next sector
813 						m_sector++;
814 						m_stat_reg |= status_interrupt;
815 						set_interrupt_line();
816 					}
817 				}
818 				break;
819 			}
820 		}
821 		break;
822 
823 	case 16:
824 	case 17:
825 	case 18:
826 	case 19:
827 	case 20:
828 	case 21:
829 	case 22:
830 	case 23:
831 	case 24:
832 	case 25:
833 	case 26:
834 	case 27:
835 	case 28:
836 	case 29:
837 	case 30:
838 	case 31:
839 		// command register
840 		if (data)
841 			m_cmd_reg |= 1 << (offset-16);
842 		else
843 			m_cmd_reg &= ~(1 << (offset-16));
844 		if (offset == 31)
845 			do_cmd();
846 		break;
847 	}
848 }
849 
850 #if 0
851 LEGACY_FLOPPY_OPTIONS_START(fd800)
852 	// SSSD 8"
853 	LEGACY_FLOPPY_OPTION(fd800, "dsk", "TI990 8\" SSSD disk image", basicdsk_identify_default, basicdsk_construct_default, nullptr,
854 		HEADS([1])
855 		TRACKS([77])
856 		SECTORS([26])
857 		SECTOR_LENGTH([128])
858 		FIRST_SECTOR_ID([1]))
859 
860 	// DSSD 8"
861 	LEGACY_FLOPPY_OPTION(fd800, "dsk", "TI990 8\" DSSD disk image", basicdsk_identify_default, basicdsk_construct_default, nullptr,
862 		HEADS([2])
863 		TRACKS([77])
864 		SECTORS([26])
865 		SECTOR_LENGTH([128])
866 		FIRST_SECTOR_ID([1]))
867 LEGACY_FLOPPY_OPTIONS_END
868 #endif
869 
device_start()870 void fd800_legacy_device::device_start()
871 {
872 	logerror("fd800: start\n");
873 	m_int_line.resolve();
874 
875 	for (auto & elem : m_drv)
876 	{
877 	//  m_drv[i].img = floppy_get_device(machine(), i);
878 		elem.phys_cylinder = -1;
879 		elem.log_cylinder[0] = elem.log_cylinder[1] = -1;
880 		elem.seclen = 64;
881 	}
882 }
883 
device_reset()884 void fd800_legacy_device::device_reset()
885 {
886 	logerror("fd800: reset\n");
887 	m_stat_reg = 0;
888 	m_interrupt_f_f = 1;
889 
890 	m_buf_pos = 0;
891 	m_buf_mode = bm_off;
892 }
893