1 // license:LGPL-2.1+
2 // copyright-holders:Michael Zapf
3 /****************************************************************************
4 
5     Myarc Hard and Floppy Disk Controller ("HFDC")
6 
7     The HFDC is based on the HDC9234 controller chip from Standard
8     Microsystems Corporation (SMC). It can work with up to three MFM hard disk
9     drives and up to four floppy disk drives.
10 
11     Data flow is detached from the main CPU. The HDC transfers data to/from
12     the drives using direct memory access to attached memory circuits. That
13     is, to write a sector on a drive the CPU must set up the contents in the
14     memory, then initiate a sector write operation.
15 
16     The advantage is a much higher data rate (in particular important when
17     working with hard disks) with less load for the main CPU. Also, we do not
18     need a READY line control (as seen with the WD17xx-based controllers).
19     Any kinds of asynchronous events are propagated via INTA* (configurable
20     to INTB*).
21 
22     Most of the control logic is hidden in the custom Gate Array chip. We do
23     not have details on its contents, but the specifications in the HFDC manual
24     and in the schematics are sufficient to create a (functionally) proper
25     emulation.
26 
27     The HDC9234 can also control tape drives. In early HFDC controller card
28     layouts, a socket for connecting a drive is available. However, there
29     never was a support from the DSR (firmware), so this feature was eliminated
30     in later releases.
31 
32     DIP switches
33     - Settings for step rate and track count for each floppy drive (DSK1-DSK4)
34     - CRU base address. Note that only on all other addresses than 1100, the
35       floppy drives are labeled DSK5-DSK8 by the card software.
36 
37 
38     Components
39 
40     HDC 9234      - Universal Disk Controller
41     FDC 9216      - Floppy disk data separator (8 MHz, divider is set by CD0 and CD1)
42     HDC 92C26     - MFM hard disk data separator (10 MHz, also used for 9234)
43     HDC 9223      - Analog data separator support
44     DS 1000-50    - Delay circuit
45     MM 58274BN    - Real time clock
46     HM 6264-LP15  - SRAM 8K x 8   (may also be 32K x 8)
47     27C128        - EPROM 16K x 8
48 
49     References:
50     [1] Myarc Inc.: Hard and Floppy Disk Controller / Users Manual
51 
52     Michael Zapf
53     July 2015
54 
55 *****************************************************************************/
56 
57 #include "emu.h"
58 #include "hfdc.h"
59 #include "formats/mfm_hd.h"
60 #include "formats/ti99_dsk.h"       // Format
61 
62 #define LOG_WARN        (1U<<1)    // Warnings
63 #define LOG_EMU         (1U<<2)
64 #define LOG_COMP        (1U<<3)
65 #define LOG_RAM         (1U<<4)
66 #define LOG_ROM         (1U<<5)
67 #define LOG_LINES       (1U<<6)
68 #define LOG_DMA         (1U<<7)
69 #define LOG_MOTOR       (1U<<8)
70 #define LOG_INT         (1U<<9)
71 #define LOG_CRU         (1U<<10)
72 #define LOG_CONFIG      (1U<<15)    // Configuration
73 
74 #define VERBOSE ( LOG_CONFIG | LOG_WARN )
75 #include "logmacro.h"
76 
77 DEFINE_DEVICE_TYPE_NS(TI99_HFDC, bus::ti99::peb, myarc_hfdc_device, "ti99_hfdc", "Myarc Hard and Floppy Disk Controller")
78 
79 namespace bus { namespace ti99 { namespace peb {
80 
81 #define BUFFER "ram"
82 #define FDC_TAG "hdc9234"
83 #define CLOCK_TAG "mm58274c"
84 
85 #define MOTOR_TIMER 1
86 
87 #define TAPE_ADDR   0x0fc0
88 #define HDC_R_ADDR  0x0fd0
89 #define HDC_W_ADDR  0x0fd2
90 #define CLK_ADDR    0x0fe0
91 #define RAM_ADDR    0x1000
92 
93 // =========================================================================
94 
95 /*
96    Constructor for the HFDC card.
97 */
myarc_hfdc_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)98 myarc_hfdc_device::myarc_hfdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock):
99 	device_t(mconfig, TI99_HFDC, tag, owner, clock),
100 	device_ti99_peribox_card_interface(mconfig, *this),
101 	m_motor_on_timer(nullptr),
102 	m_hdc9234(*this, FDC_TAG),
103 	m_clock(*this, CLOCK_TAG), m_current_floppy(nullptr),
104 	m_current_harddisk(nullptr), m_see_switches(false),
105 	m_irq(), m_dip(), m_motor_running(false),
106 	m_inDsrArea(false), m_HDCsel(false), m_RTCsel(false),
107 	m_tapesel(false), m_RAMsel(false), m_ROMsel(false), m_address(0),
108 	m_wait_for_hd1(false), m_dsrrom(nullptr), m_rom_page(0),
109 	m_buffer_ram(*this, BUFFER), m_status_latch(0), m_dma_address(0),
110 	m_output1_latch(0), m_output2_latch(0), m_lastval(0), m_MOTOR_ON(), m_readyflags(0)
111 {
112 }
113 
setaddress_dbin(offs_t offset,int state)114 void myarc_hfdc_device::setaddress_dbin(offs_t offset, int state)
115 {
116 	// Do not allow setaddress for the debugger. It will mess up the
117 	// setaddress/memory access pairs when the CPU enters wait states.
118 	if (machine().side_effects_disabled()) return;
119 
120 	// Selection login in the PAL and some circuits on the board
121 
122 	// Is the card being selected?
123 	// Area = 4000-5fff
124 	// 010x xxxx xxxx xxxx
125 	m_address = offset;
126 
127 	m_inDsrArea = in_dsr_space(m_address, true);
128 
129 	if (!m_inDsrArea) return;
130 
131 	// Is the HDC chip on the card being selected?
132 	// HDC9234: read: 4fd0,4 (mirror 8,c)
133 	// HDC9234: write: 4fd2,6 (mirror a,e)
134 	// read:  ...0 1111 1101 xx00
135 	// write: ...0 1111 1101 xx10
136 
137 	m_HDCsel = m_inDsrArea &&
138 				((state==ASSERT_LINE && ((m_address & 0x1ff3)==HDC_R_ADDR))    // read
139 				|| (state==CLEAR_LINE && ((m_address & 0x1ff3)==HDC_W_ADDR)));  // write
140 
141 	// Is the tape selected?
142 	// ...0 1111 1100 xxxx
143 	m_tapesel = m_inDsrArea && ((m_address & 0x1ff0)==TAPE_ADDR);
144 
145 	// Is the RTC selected on the card? (even addr)
146 	// ...0 1111 111x xxx0
147 	m_RTCsel = m_inDsrArea && ((m_address & 0x1fe1)==CLK_ADDR);
148 
149 	// Is RAM selected?
150 	// ...1 xxxx xxxx xxxx
151 	m_RAMsel = m_inDsrArea && ((m_address & 0x1000)==RAM_ADDR);
152 
153 	// Is ROM selected?
154 	// not 0100 1111 11xx xxxx
155 	m_ROMsel = m_inDsrArea && !m_RAMsel && !((m_address & 0x0fc0)==0x0fc0);
156 }
157 
158 /*
159     Access for debugger. This is a stripped-down version of the
160     main methods below. We only allow ROM and RAM access.
161 */
debug_read(offs_t offset,uint8_t * value)162 void myarc_hfdc_device::debug_read(offs_t offset, uint8_t* value)
163 {
164 	if (in_dsr_space(offset, true) && m_selected)
165 	{
166 		if ((offset & 0x1000)==RAM_ADDR)
167 		{
168 			int bank = (offset & 0x0c00) >> 10;
169 			*value = m_buffer_ram->pointer()[(m_ram_page[bank]<<10) | (offset & 0x03ff)];
170 		}
171 		else
172 		{
173 			if ((offset & 0x0fc0)!=0x0fc0)
174 			{
175 				*value = m_dsrrom[(m_rom_page << 12) | (offset & 0x0fff)];
176 			}
177 		}
178 	}
179 }
180 
debug_write(offs_t offset,uint8_t data)181 void myarc_hfdc_device::debug_write(offs_t offset, uint8_t data)
182 {
183 	if (in_dsr_space(offset, true) && m_selected)
184 	{
185 		if ((offset & 0x1000)==RAM_ADDR)
186 		{
187 			int bank = (offset & 0x0c00) >> 10;
188 			m_buffer_ram->pointer()[(m_ram_page[bank]<<10) | (m_address & 0x03ff)] = data;
189 		}
190 	}
191 }
192 
193 /*
194     Read a byte from the memory address space of the HFDC
195 
196     0x4000 - 0x4fbf one of four possible ROM pages
197     0x4fc0 - 0x4fcf Tape control (only available in prototype HFDC models)
198     0x4fd0 - 0x4fdf HDC 9234 ports
199     0x4fe0 - 0x4fff RTC chip ports
200 
201     0x5000 - 0x53ff static RAM page 0x08
202     0x5400 - 0x57ff static RAM page any of 32 pages
203     0x5800 - 0x5bff static RAM page any of 32 pages
204     0x5c00 - 0x5fff static RAM page any of 32 pages
205 
206     HFDC manual, p. 44
207 */
readz(offs_t offset,uint8_t * value)208 void myarc_hfdc_device::readz(offs_t offset, uint8_t *value)
209 {
210 	if (machine().side_effects_disabled())
211 	{
212 		debug_read(offset, value);
213 		return;
214 	}
215 
216 	if (m_inDsrArea && m_selected)
217 	{
218 		if (m_tapesel)
219 		{
220 			LOGMASKED(LOG_WARN, "Tape support not available on this HFDC version (access to address %04x)\n", m_address & 0xffff);
221 			return;
222 		}
223 
224 		if (m_HDCsel)
225 		{
226 			*value = m_hdc9234->read((m_address>>2)&1);
227 			LOGMASKED(LOG_COMP, "%04x[HDC] -> %02x\n", m_address & 0xffff, *value);
228 			return;
229 		}
230 
231 		if (m_RTCsel)
232 		{
233 			*value = m_clock->read((m_address & 0x001e) >> 1);
234 			LOGMASKED(LOG_COMP, "%04x[CLK] -> %02x\n", m_address & 0xffff, *value);
235 			return;
236 		}
237 
238 		if (m_RAMsel)
239 		{
240 			// 0101 00xx xxxx xxxx  static 0x08
241 			// 0101 01xx xxxx xxxx  bank 1
242 			// 0101 10xx xxxx xxxx  bank 2
243 			// 0101 11xx xxxx xxxx  bank 3
244 			int bank = (m_address & 0x0c00) >> 10;
245 
246 			// If a DMA is in progress, do not respond
247 			if (m_dip == CLEAR_LINE) *value = m_buffer_ram->pointer()[(m_ram_page[bank]<<10) | (m_address & 0x03ff)];
248 			if (WORD_ALIGNED(m_address))
249 			{
250 				int valword = (((*value) << 8) | m_buffer_ram->pointer()[(m_ram_page[bank]<<10) | ((m_address+1) & 0x03ff)])&0xffff;
251 				LOGMASKED(LOG_RAM, "%04x[%02x] -> %04x\n", m_address & 0xffff, m_ram_page[bank], valword);
252 			}
253 			return;
254 		}
255 
256 		if (m_ROMsel)
257 		{
258 			*value = m_dsrrom[(m_rom_page << 12) | (m_address & 0x0fff)];
259 			if (WORD_ALIGNED(m_address))
260 			{
261 				int valword = (((*value) << 8) | m_dsrrom[(m_rom_page << 12) | ((m_address + 1) & 0x0fff)])&0xffff;
262 				LOGMASKED(LOG_ROM, "%04x[%02x] -> %04x\n", m_address & 0xffff, m_rom_page, valword);
263 			}
264 			return;
265 		}
266 	}
267 }
268 
269 /*
270     Write a byte to the memory address space of the HFDC
271 
272     0x4fc0 - 0x4fcf Tape control (only available in prototype HFDC models)
273     0x4fd0 - 0x4fdf HDC 9234 ports
274     0x4fe0 - 0x4fff RTC chip ports
275 
276     0x5000 - 0x53ff static RAM page 0x08
277     0x5400 - 0x57ff static RAM page any of 32 pages
278     0x5800 - 0x5bff static RAM page any of 32 pages
279     0x5c00 - 0x5fff static RAM page any of 32 pages
280 */
write(offs_t offset,uint8_t data)281 void myarc_hfdc_device::write(offs_t offset, uint8_t data)
282 {
283 	if (machine().side_effects_disabled())
284 	{
285 		debug_write(offset, data);
286 		return;
287 	}
288 
289 	if (m_inDsrArea && m_selected)
290 	{
291 		if (m_tapesel)
292 		{
293 			LOGMASKED(LOG_WARN, "Tape support not available on this HFDC version (write access to address %04x: %02x)\n", m_address & 0xffff, data);
294 			return;
295 		}
296 
297 		if (m_HDCsel)
298 		{
299 			LOGMASKED(LOG_COMP, "%04x[HDC] <- %02x\n", m_address & 0xffff, data);
300 			m_hdc9234->write((m_address>>2)&1, data);
301 			return;
302 		}
303 
304 		if (m_RTCsel)
305 		{
306 			LOGMASKED(LOG_COMP, "%04x[CLK] <- %02x\n", m_address & 0xffff, data);
307 			m_clock->write((m_address & 0x001e) >> 1, data);
308 			return;
309 		}
310 
311 		if (m_RAMsel)
312 		{
313 			// 0101 00xx xxxx xxxx  static 0x08
314 			// 0101 01xx xxxx xxxx  bank 1
315 			// 0101 10xx xxxx xxxx  bank 2
316 			// 0101 11xx xxxx xxxx  bank 3
317 			int bank = (m_address & 0x0c00) >> 10;
318 			LOGMASKED(LOG_RAM, "%04x[%02x] <- %02x\n", m_address & 0xffff, m_ram_page[bank], data);
319 
320 			// When a DMA is in progress, do not change anything
321 			if (m_dip == CLEAR_LINE) m_buffer_ram->pointer()[(m_ram_page[bank]<<10) | (m_address & 0x03ff)] = data;
322 			return;
323 		}
324 		// The rest is ROM
325 		if (m_ROMsel)
326 		{
327 			LOGMASKED(LOG_ROM, "Ignoring write ROM %04x[%02x]: %02x\n", m_address & 0xffff, m_rom_page, data);
328 		}
329 	}
330 }
331 
332 /*
333     Read a set of 8 bits in the CRU space of the HFDC
334     There are two banks, according to the state of m_see_switches
335 
336     m_see_switches == true:
337 
338        7     6     5     4     3     2     1     0      CRU bit
339     +-----+-----+-----+-----+-----+-----+-----+-----+
340     |DIP5*|DIP6*|DIP7*|DIP8*|DIP1*|DIP2*|DIP3*|DIP4*|
341     +-----+-----+-----+-----+-----+-----+-----+-----+
342     |   DSK3    |   DSK4    |   DSK1    |   DSK2    |
343     +-----+-----+-----+-----+-----+-----+-----+-----+
344 
345     Settings for DSKn: (n=1..4)
346 
347     DIP(2n-1) DIP(2n)   Tracks     Step(ms)    Sectors (256 byte)
348     off       off        40        16          18/16/9
349     on        off        40        8           18/16/9
350     off       on         80/40     2           18/16/9
351     on        on         80        2           36
352 
353     Inverted logic: switch=on means a 0 bit, off is a 1 bit when read by the CRU
354 
355     Caution: The last setting is declared as "future expansion" and is
356     locked to a 1.44 MiB capacity. No lower formats can be used.
357 
358     ---
359 
360     m_see_switches == false:
361 
362        7     6     5     4     3     2     1     0
363     +-----+-----+-----+-----+-----+-----+-----+-----+
364     |  0  |  0  |  0  |  0  | WAIT| MON*| DIP | IRQ |
365     +-----+-----+-----+-----+-----+-----+-----+-----+
366 
367     WAIT = Wait for WDS1 to become ready
368     MON* = Motor on
369     DIP = DMA in progress
370     IRQ = Interrupt request
371     ---
372     0 on all other locations
373 */
crureadz(offs_t offset,uint8_t * value)374 void myarc_hfdc_device::crureadz(offs_t offset, uint8_t *value)
375 {
376 	uint8_t reply;
377 	if ((offset & 0xff00)==m_cru_base)
378 	{
379 		if ((offset & 0x00f0)==0)  // CRU bits 0-7
380 		{
381 			if (m_see_switches)
382 			{
383 				reply = ~(ioport("HFDCDIP")->read());
384 			}
385 			else
386 			{
387 				reply = 0;
388 				if (m_irq == ASSERT_LINE)  reply |= 0x01;
389 				if (m_dip == ASSERT_LINE)  reply |= 0x02;
390 				if (!m_motor_running) reply |= 0x04;
391 				if (m_wait_for_hd1) reply |= 0x08;
392 			}
393 			*value = BIT(reply, (offset >> 1) & 7);
394 		}
395 		else   // CRU bits 8+
396 		{
397 			*value = 0;
398 		}
399 
400 		LOGMASKED(LOG_CRU, "CRU %04x -> %02x\n", offset & 0xffff, *value);
401 	}
402 }
403 
404 /*
405     Set a bit in the CRU space of the HFDC
406 
407        7     6     5     4     3     2     1     0
408     +-----+-----+-----+-----+-----+-----+-----+-----+
409     |  -  |  -  |  -  | ROM1| ROM0| MON | RES*| SEL |
410     |     |     |     | CSEL| CD1 | CD0 |     |     |
411     +-----+-----+-----+-----+-----+-----+-----+-----+
412 
413        17    16    15    14    13    12    11    10    F     E     D     C     B     A     9     8
414     +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
415     |    RAM page select @5C00    |    RAM page select @5800    |     RAM page select @5400   |  -  |
416     +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
417 
418     SEL  = Select card (and map ROM into address space)
419     RES* = Reset controller
420     MON  = Motor on / same line goes to CD0 input of floppy separator
421     ROM bank select: bank 0..3; bit 3 = MSB, 4 = LSB
422     RAM bank select: bank 0..31; bit 9 = LSB (accordingly for other two areas)
423     CD0 and CD1 are Clock Divider selections for the Floppy Data Separator (FDC9216)
424     CSEL = CRU input select (m_see_switches)
425 
426     HFDC manual p. 43
427 */
cruwrite(offs_t offset,uint8_t data)428 void myarc_hfdc_device::cruwrite(offs_t offset, uint8_t data)
429 {
430 	if ((offset & 0xff00)==m_cru_base)
431 	{
432 		LOGMASKED(LOG_CRU, "CRU %04x <- %d\n", offset & 0xffff, data);
433 
434 		int bit = (offset >> 1) & 0x1f;
435 
436 		// Handle the page selects right here
437 		if (bit >= 0x09 && bit < 0x18)
438 		{
439 			if (data)
440 				// we leave index 0 unchanged; modify indices 1-3
441 				m_ram_page[(bit-4)/5] |= 1 << ((bit-9)%5);
442 			else
443 				m_ram_page[(bit-4)/5] &= ~(1 << ((bit-9)%5));
444 
445 			if (bit==0x0d) LOGMASKED(LOG_CRU, "RAM page @5400 = %d\n", m_ram_page[1]);
446 			if (bit==0x12) LOGMASKED(LOG_CRU, "RAM page @5800 = %d\n", m_ram_page[2]);
447 			if (bit==0x17) LOGMASKED(LOG_CRU, "RAM page @5C00 = %d\n", m_ram_page[3]);
448 			return;
449 		}
450 
451 		switch (bit)
452 		{
453 		case 0:
454 			{
455 				bool turnOn = (data!=0);
456 				// Avoid too many meaningless log outputs
457 				if (m_selected != turnOn) LOGMASKED(LOG_CRU, "card %s\n", turnOn? "selected" : "unselected");
458 				m_selected = turnOn;
459 				break;
460 			}
461 		case 1:
462 			if (data==0) LOGMASKED(LOG_CRU, "trigger HDC reset\n");
463 			m_hdc9234->reset((data == 0)? ASSERT_LINE : CLEAR_LINE);
464 			break;
465 
466 		case 2:
467 			m_hdc9234->set_clock_divider(0, data);
468 
469 			// Activate motor
470 			// When 1, let motor run continuously. When 0, a simple monoflop circuit keeps the line active for another 4 sec
471 			if (data==1)
472 			{
473 				m_motor_on_timer->reset();
474 				set_floppy_motors_running(true);
475 			}
476 			else
477 			{
478 				m_motor_on_timer->adjust(attotime::from_msec(4230));
479 			}
480 			m_lastval = data;
481 			break;
482 
483 		case 3:
484 			m_hdc9234->set_clock_divider(1, data);
485 			m_rom_page = (data != 0)? (m_rom_page | 2) : (m_rom_page & 0xfd);
486 			LOGMASKED(LOG_CRU, "ROM page = %d\n", m_rom_page);
487 			break;
488 
489 		case 4:
490 			m_see_switches = (data != 0);
491 			m_rom_page = (data != 0)? (m_rom_page | 1) : (m_rom_page & 0xfe);
492 			LOGMASKED(LOG_CRU, "ROM page = %d, see_switches = %d\n", m_rom_page, m_see_switches);
493 			break;
494 
495 		default:
496 			LOGMASKED(LOG_WARN, "Attempt to set undefined CRU bit %d\n", bit);
497 		}
498 	}
499 }
500 
501 /*
502     Monoflop has gone back to the OFF state.
503 */
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)504 void myarc_hfdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
505 {
506 	set_floppy_motors_running(false);
507 }
508 
509 /*
510     This is called back from the floppy when an index hole is passing by.
511 */
floppy_index_callback(floppy_image_device * floppy,int state)512 void myarc_hfdc_device::floppy_index_callback(floppy_image_device *floppy, int state)
513 {
514 	if (state==1) LOGMASKED(LOG_LINES, "Floppy index pulse\n");
515 	// m_status_latch = (state==ASSERT_LINE)? (m_status_latch | hdc92x4_device::DS_INDEX) :  (m_status_latch & ~hdc92x4_device::DS_INDEX);
516 	set_bits(m_status_latch, hdc92x4_device::DS_INDEX, (state==ASSERT_LINE));
517 	signal_drive_status();
518 }
519 
520 /*
521     This is called back from the hard disk when an index hole is passing by.
522 */
harddisk_index_callback(mfm_harddisk_device * harddisk,int state)523 void myarc_hfdc_device::harddisk_index_callback(mfm_harddisk_device *harddisk, int state)
524 {
525 	if (state==1) LOGMASKED(LOG_LINES, "HD index pulse\n");
526 	set_bits(m_status_latch, hdc92x4_device::DS_INDEX, (state==ASSERT_LINE));
527 	signal_drive_status();
528 }
529 
530 /*
531     This is called back from the hard disk when READY becomes asserted.
532 */
harddisk_ready_callback(mfm_harddisk_device * harddisk,int state)533 void myarc_hfdc_device::harddisk_ready_callback(mfm_harddisk_device *harddisk, int state)
534 {
535 	LOGMASKED(LOG_LINES, "HD READY = %d\n", state);
536 	set_bits(m_status_latch, hdc92x4_device::DS_READY, (state==ASSERT_LINE));
537 	signal_drive_status();
538 }
539 
540 /*
541     This is called back from the hard disk when seek_complete becomes asserted.
542 */
harddisk_skcom_callback(mfm_harddisk_device * harddisk,int state)543 void myarc_hfdc_device::harddisk_skcom_callback(mfm_harddisk_device *harddisk, int state)
544 {
545 	LOGMASKED(LOG_LINES, "HD seek complete = %d\n", state);
546 	set_bits(m_status_latch, hdc92x4_device::DS_SKCOM, (state==ASSERT_LINE));
547 	signal_drive_status();
548 }
549 
set_bits(uint8_t & byte,int mask,bool set)550 void myarc_hfdc_device::set_bits(uint8_t& byte, int mask, bool set)
551 {
552 	if (set) byte |= mask;
553 	else byte &= ~mask;
554 }
555 
556 /*
557    Maps the set bit to an index. The rightmost 1 bit is significant. When no
558    bit is set, returns -1.
559 */
bit_to_index(int value)560 int myarc_hfdc_device::bit_to_index(int value)
561 {
562 	if (value & 0x01) return 0;
563 	if (value & 0x02) return 1;
564 	if (value & 0x04) return 2;
565 	if (value & 0x08) return 3;
566 	return -1;
567 }
568 
569 /*
570     Notify the controller about the status change
571 */
signal_drive_status()572 void myarc_hfdc_device::signal_drive_status()
573 {
574 	uint8_t reply = 0;
575 	// Status byte as defined by HDC9234
576 	// +------+------+------+------+------+------+------+------+
577 	// | ECC  |Index | SeekC| Tr00 | User | WrPrt| Ready|Fault |
578 	// +------+------+------+------+------+------+------+------+
579 	//
580 	// Set by HFDC
581 	// 74LS240 is used for driving the lines; it also inverts the inputs
582 	// If no hard drive or floppy is connected, all lines are 0
583 	// +------+------+------+------+------+------+------+------+
584 	// |  0   | Index| SeekC| Tr00 |   0  | WrPrt| Ready|Fault |
585 	// +------+------+------+------+------+------+------+------+
586 	//
587 	//  Ready = /WDS.ready* | DSK
588 	//  SeekComplete = /WDS.seekComplete* | DSK
589 
590 	// If DSK is selected, set Ready and SeekComplete to 1
591 	if ((m_output1_latch & 0x10)!=0)
592 	{
593 		reply |= 0x22;
594 
595 		// Check for TRK00*
596 		if ((m_current_floppy != nullptr) && (!m_current_floppy->trk00_r()))
597 			reply |= hdc92x4_device::DS_TRK00;
598 	}
599 	else
600 	{
601 		if ((m_output1_latch & 0xe0)!=0)
602 		{
603 			if (m_current_harddisk != nullptr)
604 			{
605 				if (m_current_harddisk->ready_r()==ASSERT_LINE)
606 				{
607 					m_status_latch |= hdc92x4_device::DS_READY;
608 					set_bits(m_status_latch, hdc92x4_device::DS_SKCOM, m_current_harddisk->seek_complete_r()==ASSERT_LINE);
609 					set_bits(m_status_latch, hdc92x4_device::DS_TRK00, m_current_harddisk->trk00_r()==ASSERT_LINE);
610 				}
611 			}
612 			// If WDS is selected but not connected, WDS.ready* and WDS.seekComplete* are 1, so Ready=SeekComplete=0
613 			else set_bits(m_status_latch, hdc92x4_device::DS_READY | hdc92x4_device::DS_SKCOM, false);
614 		}
615 	}
616 
617 	reply |= m_status_latch;
618 
619 	m_hdc9234->auxbus_in(reply);
620 }
621 
622 /*
623     When the HDC outputs a byte via its AB (auxiliary bus), we need to latch it.
624     The target of the transfer is determined by two control lines (S1,S0).
625     (0,0) = input drive status
626     (0,1) = DMA address
627     (1,0) = OUTPUT1
628     (1,1) = OUTPUT2
629 */
auxbus_out(offs_t offset,uint8_t data)630 void myarc_hfdc_device::auxbus_out(offs_t offset, uint8_t data)
631 {
632 	int index;
633 	switch (offset)
634 	{
635 	case hdc92x4_device::INPUT_STATUS:
636 		LOGMASKED(LOG_WARN, "Invalid operation: S0=S1=0, but tried to write (expected: read drive status)\n");
637 		break;
638 
639 	case hdc92x4_device::OUTPUT_DMA_ADDR:
640 		// Value is dma address byte. Shift previous contents to the left.
641 		// The value is latched inside the Gate Array.
642 		m_dma_address = ((m_dma_address << 8) + (data&0xff))&0xffffff;
643 		LOGMASKED(LOG_DMA, "Setting DMA address; current value = %06x\n", m_dma_address);
644 		break;
645 
646 	case hdc92x4_device::OUTPUT_1:
647 		// value is output1
648 		// The HFDC interprets the value as follows:
649 		// WDS = Winchester Drive System, old name for hard disk
650 		// +------+------+------+------+------+------+------+------+
651 		// | WDS3 | WDS2 | WDS1 | DSKx | x=4  | x=3  | x=2  | x=1  |
652 		// +------+------+------+------+------+------+------+------+
653 		// Accordingly, drive 0 is always the floppy; selected by the low nibble
654 
655 		m_output1_latch = data;
656 
657 		if ((data & 0x10) != 0) connect_floppy_unit(bit_to_index(data & 0x0f));             // Floppy selected
658 		else
659 		{
660 			index = bit_to_index((data>>4) & 0x0f);
661 
662 			if (index > 0) connect_harddisk_unit(index-1);  // HD selected; index >= 1
663 			else
664 			{
665 				disconnect_floppy_drives();
666 				disconnect_hard_drives();
667 
668 				// Turn off READY and SEEK COMPLETE
669 				set_bits(m_status_latch, hdc92x4_device::DS_READY | hdc92x4_device::DS_SKCOM, false);
670 			}
671 		}
672 		break;
673 
674 	case hdc92x4_device::OUTPUT_2:
675 		// value is output2
676 		// DS3* = /WDS3
677 		// WCur = Reduced Write Current
678 		// Dir = Step direction
679 		// Step = Step pulse
680 		// Head = Selected head number (floppy: 0000 or 0001)
681 		// +------+------+------+------+------+------+------+------+
682 		// | DS3* | WCur | Dir  | Step |           Head            |
683 		// +------+------+------+------+------+------+------+------+
684 		m_output2_latch = data;
685 
686 		// Output the step pulse to the selected floppy drive
687 		if (m_current_floppy != nullptr)
688 		{
689 			m_current_floppy->ss_w(data & 0x01);
690 			m_current_floppy->dir_w((data & 0x20)==0);
691 			m_current_floppy->stp_w((data & 0x10)==0);
692 		}
693 
694 		if (m_current_harddisk != nullptr)
695 		{
696 			// Dir = 0 -> outward
697 			m_current_harddisk->direction_in_w((data & 0x20)? ASSERT_LINE : CLEAR_LINE);
698 			m_current_harddisk->step_w((data & 0x10)? ASSERT_LINE : CLEAR_LINE);
699 			m_current_harddisk->headsel_w(data & 0x0f);
700 		}
701 
702 		// We are pushing the drive status after OUTPUT2
703 		signal_drive_status();
704 		break;
705 	}
706 }
707 
708 enum
709 {
710 	HFDC_FLOPPY = 1,
711 	HFDC_HARDDISK = 2
712 };
713 
connect_floppy_unit(int index)714 void myarc_hfdc_device::connect_floppy_unit(int index)
715 {
716 	// Check if we have a new floppy
717 	if (m_floppy_unit[index] != m_current_floppy)
718 	{
719 		// Clear all latched flags from other drives
720 		m_status_latch = 0;
721 		disconnect_floppy_drives();
722 		LOGMASKED(LOG_LINES, "Select floppy drive DSK%d\n", index+1);
723 
724 		// Connect new drive
725 		m_current_floppy = m_floppy_unit[index];
726 
727 		// We don't use the READY line of floppy drives.
728 		// READY is asserted when DSKx = 1
729 		// The controller fetches the state with the auxbus access
730 		LOGMASKED(LOG_LINES, "Connect index callback DSK%d\n", index+1);
731 		if (m_current_floppy != nullptr)
732 			m_current_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(&myarc_hfdc_device::floppy_index_callback, this));
733 		else
734 			LOGMASKED(LOG_WARN, "Connection to DSK%d failed because no drive is connected\n", index+1);
735 		m_hdc9234->connect_floppy_drive(m_floppy_unit[index]);
736 	}
737 
738 	// We can only run a floppy or a harddisk at a time, not both
739 	disconnect_hard_drives();
740 }
741 
connect_harddisk_unit(int index)742 void myarc_hfdc_device::connect_harddisk_unit(int index)
743 {
744 	if (m_harddisk_unit[index] != m_current_harddisk)
745 	{
746 		// Clear all latched flags form other drives
747 		m_status_latch = 0;
748 		disconnect_hard_drives();
749 		LOGMASKED(LOG_LINES, "Select hard disk WDS%d\n", index+1);
750 
751 		// Connect new drive
752 		m_current_harddisk = m_harddisk_unit[index];
753 
754 		LOGMASKED(LOG_LINES, "Connect index callback WDS%d\n", index+1);
755 		if (m_current_harddisk != nullptr)
756 		{
757 			m_current_harddisk->setup_index_pulse_cb(mfm_harddisk_device::index_pulse_cb(&myarc_hfdc_device::harddisk_index_callback, this));
758 			m_current_harddisk->setup_ready_cb(mfm_harddisk_device::ready_cb(&myarc_hfdc_device::harddisk_ready_callback, this));
759 			m_current_harddisk->setup_seek_complete_cb(mfm_harddisk_device::seek_complete_cb(&myarc_hfdc_device::harddisk_skcom_callback, this));
760 		}
761 		else
762 			LOGMASKED(LOG_WARN, "Connection to WDS%d failed because no drive is connected\n", index+1);
763 		m_hdc9234->connect_hard_drive(m_current_harddisk);
764 	}
765 
766 	// We can only run a floppy or a harddisk at a time, not both
767 	disconnect_floppy_drives();
768 }
769 
disconnect_floppy_drives()770 void myarc_hfdc_device::disconnect_floppy_drives()
771 {
772 	LOGMASKED(LOG_LINES, "Unselect floppy drives\n");
773 	// Disconnect current floppy
774 	if (m_current_floppy != nullptr)
775 	{
776 		m_current_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb());
777 		m_current_floppy = nullptr;
778 	}
779 }
780 
disconnect_hard_drives()781 void myarc_hfdc_device::disconnect_hard_drives()
782 {
783 	LOGMASKED(LOG_LINES, "Unselect hard drives\n");
784 	if (m_current_harddisk != nullptr)
785 	{
786 		m_current_harddisk->setup_index_pulse_cb(mfm_harddisk_device::index_pulse_cb());
787 		m_current_harddisk->setup_seek_complete_cb(mfm_harddisk_device::seek_complete_cb());
788 		m_current_harddisk = nullptr;
789 	}
790 }
791 
792 /*
793     All floppy motors are operated by the same line.
794 */
set_floppy_motors_running(bool run)795 void myarc_hfdc_device::set_floppy_motors_running(bool run)
796 {
797 	if (run)
798 	{
799 		if (m_MOTOR_ON==CLEAR_LINE) LOGMASKED(LOG_MOTOR, "Motor START\n");
800 		m_MOTOR_ON = ASSERT_LINE;
801 	}
802 	else
803 	{
804 		if (m_MOTOR_ON==ASSERT_LINE) LOGMASKED(LOG_MOTOR, "Motor STOP\n");
805 		m_MOTOR_ON = CLEAR_LINE;
806 	}
807 
808 	// Set all motors
809 	for (auto & elem : m_floppy_unit)
810 		if (elem != nullptr) elem->mon_w((run)? 0 : 1);
811 }
812 
813 /*
814     Called whenever the state of the HDC9234 interrupt pin changes.
815 */
WRITE_LINE_MEMBER(myarc_hfdc_device::intrq_w)816 WRITE_LINE_MEMBER( myarc_hfdc_device::intrq_w )
817 {
818 	m_irq = (line_state)state;
819 	LOGMASKED(LOG_INT, "INT pin from controller = %d, propagating to INTA*\n", state);
820 
821 	// Set INTA*
822 	// Signal from SMC is active high, INTA* is active low; board inverts signal
823 	// Anyway, we stay with ASSERT_LINE and CLEAR_LINE
824 	m_slot->set_inta(state);
825 }
826 
827 /*
828     Called whenever the HDC9234 desires bus access to the buffer RAM. The
829     controller expects a call to dmarq in 1 byte time.
830 */
WRITE_LINE_MEMBER(myarc_hfdc_device::dmarq_w)831 WRITE_LINE_MEMBER( myarc_hfdc_device::dmarq_w )
832 {
833 	LOGMASKED(LOG_DMA, "DMARQ pin from controller = %d\n", state);
834 	if (state == ASSERT_LINE)
835 	{
836 		m_hdc9234->dmaack(ASSERT_LINE);
837 	}
838 }
839 
840 /*
841     Called whenever the state of the HDC9234 DMA in progress changes.
842 */
WRITE_LINE_MEMBER(myarc_hfdc_device::dip_w)843 WRITE_LINE_MEMBER( myarc_hfdc_device::dip_w )
844 {
845 	m_dip = (line_state)state;
846 }
847 
848 /*
849     Read a byte from the onboard SRAM. This is called from the HDC9234.
850 */
read_buffer()851 uint8_t myarc_hfdc_device::read_buffer()
852 {
853 	LOGMASKED(LOG_DMA, "Read access to onboard SRAM at %04x\n", m_dma_address);
854 	if (m_dma_address > 0x8000) LOGMASKED(LOG_WARN, "Read access beyond RAM size: %06x\n", m_dma_address);
855 	uint8_t value = m_buffer_ram->pointer()[m_dma_address & 0x7fff];
856 	m_dma_address = (m_dma_address+1) & 0x7fff;
857 	return value;
858 }
859 
860 /*
861     Write a byte to the onboard SRAM. This is called from the HDC9234.
862 */
write_buffer(uint8_t data)863 void myarc_hfdc_device::write_buffer(uint8_t data)
864 {
865 	LOGMASKED(LOG_DMA, "Write access to onboard SRAM at %04x: %02x\n", m_dma_address, data);
866 	if (m_dma_address > 0x8000) LOGMASKED(LOG_WARN, "Write access beyond RAM size: %06x\n", m_dma_address);
867 	m_buffer_ram->pointer()[m_dma_address & 0x7fff] = data;
868 	m_dma_address = (m_dma_address+1) & 0x7fff;
869 }
870 
device_start()871 void myarc_hfdc_device::device_start()
872 {
873 	m_dsrrom = memregion(TI99_DSRROM)->base();
874 	m_motor_on_timer = timer_alloc(MOTOR_TIMER);
875 	// The HFDC does not use READY; it has on-board RAM for DMA
876 	m_current_floppy = nullptr;
877 	m_current_harddisk = nullptr;
878 
879 	// Parent class members
880 	save_item(NAME(m_senila));
881 	save_item(NAME(m_senilb));
882 	save_item(NAME(m_selected));
883 	save_item(NAME(m_cru_base));
884 
885 	// Own members
886 	save_item(NAME(m_see_switches));
887 	save_item(NAME(m_irq));
888 	save_item(NAME(m_dip));
889 	save_item(NAME(m_motor_running));
890 	save_item(NAME(m_inDsrArea));
891 	save_item(NAME(m_HDCsel));
892 	save_item(NAME(m_RTCsel));
893 	save_item(NAME(m_tapesel));
894 	save_item(NAME(m_RAMsel));
895 	save_item(NAME(m_ROMsel));
896 	save_item(NAME(m_address));
897 	save_item(NAME(m_wait_for_hd1));
898 	save_item(NAME(m_rom_page));
899 	save_pointer(NAME(m_ram_page),4);
900 	save_item(NAME(m_status_latch));
901 	save_item(NAME(m_dma_address));
902 	save_item(NAME(m_output1_latch));
903 	save_item(NAME(m_output2_latch));
904 	save_item(NAME(m_lastval));
905 	save_item(NAME(m_MOTOR_ON));
906 	save_item(NAME(m_readyflags));
907 }
908 
device_reset()909 void myarc_hfdc_device::device_reset()
910 {
911 	m_cru_base = ioport("CRUHFDC")->read();
912 	m_wait_for_hd1 = ioport("WAITHD1")->read();
913 
914 	// Resetting values
915 	m_rom_page = 0;
916 
917 	m_ram_page[0] = 0x08;   // static page 0x08
918 	for (int i=1; i < 4; i++) m_ram_page[i] = 0;
919 
920 	m_output1_latch = m_output2_latch = 0;
921 
922 	m_status_latch = 0x00;
923 
924 	m_dip = m_irq = CLEAR_LINE;
925 	m_see_switches = false;
926 	m_motor_running = false;
927 	m_selected = false;
928 	m_lastval = 0;
929 	m_readyflags = 0;
930 
931 	for (int i=0; i < 4; i++)
932 	{
933 		if (m_floppy_unit[i] != nullptr)
934 			LOGMASKED(LOG_CONFIG, "FD connector %d with %s\n", i+1, m_floppy_unit[i]->name());
935 		else
936 			LOGMASKED(LOG_CONFIG, "FD connector %d has no floppy attached\n", i+1);
937 	}
938 
939 	for (int i=0; i < 3; i++)
940 	{
941 		if (m_harddisk_unit[i] != nullptr)
942 			LOGMASKED(LOG_CONFIG, "HD connector %d with %s\n", i+1, m_harddisk_unit[i]->name());
943 		else
944 			LOGMASKED(LOG_CONFIG, "HD connector %d has no drive attached\n", i+1);
945 	}
946 
947 	// Disconnect all units
948 	disconnect_floppy_drives();
949 	disconnect_hard_drives();
950 }
951 
device_config_complete()952 void myarc_hfdc_device::device_config_complete()
953 {
954 	for (int i=0; i < 3; i++)
955 	{
956 		m_floppy_unit[i] = nullptr;
957 		m_harddisk_unit[i] = nullptr;
958 	}
959 	m_floppy_unit[3] = nullptr;
960 
961 	// Seems to be null when doing a "-listslots"
962 	if (subdevice("f1")!=nullptr)
963 	{
964 		m_floppy_unit[0] = static_cast<floppy_connector*>(subdevice("f1"))->get_device();
965 		m_floppy_unit[1] = static_cast<floppy_connector*>(subdevice("f2"))->get_device();
966 		m_floppy_unit[2] = static_cast<floppy_connector*>(subdevice("f3"))->get_device();
967 		m_floppy_unit[3] = static_cast<floppy_connector*>(subdevice("f4"))->get_device();
968 
969 		m_harddisk_unit[0] = static_cast<mfm_harddisk_connector*>(subdevice("h1"))->get_device();
970 		m_harddisk_unit[1] = static_cast<mfm_harddisk_connector*>(subdevice("h2"))->get_device();
971 		m_harddisk_unit[2] = static_cast<mfm_harddisk_connector*>(subdevice("h3"))->get_device();
972 	}
973 }
974 
975 /*
976     The HFDC controller can be configured for different CRU base addresses,
977     but DSK1-DSK4 are only available for CRU 1100. For all other addresses,
978     the drives 1 to 4 are renamed to DSK5-DSK8 (see [1] p. 7).
979 */
980 INPUT_PORTS_START( ti99_hfdc )
981 	PORT_START( "WAITHD1" )
982 	PORT_DIPNAME( 0x01, 0x00, "HFDC Wait for HD1" )
DEF_STR(Off)983 		PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
984 		PORT_DIPSETTING( 0x01, DEF_STR( On ) )
985 
986 	PORT_START( "CRUHFDC" )
987 	PORT_DIPNAME( 0x1f00, 0x1100, "HFDC CRU base" )
988 		PORT_DIPSETTING( 0x1000, "1000" )
989 		PORT_DIPSETTING( 0x1100, "1100" )
990 		PORT_DIPSETTING( 0x1200, "1200" )
991 		PORT_DIPSETTING( 0x1300, "1300" )
992 		PORT_DIPSETTING( 0x1400, "1400" )
993 		PORT_DIPSETTING( 0x1500, "1500" )
994 		PORT_DIPSETTING( 0x1600, "1600" )
995 		PORT_DIPSETTING( 0x1700, "1700" )
996 		PORT_DIPSETTING( 0x1800, "1800" )
997 		PORT_DIPSETTING( 0x1900, "1900" )
998 		PORT_DIPSETTING( 0x1a00, "1A00" )
999 		PORT_DIPSETTING( 0x1b00, "1B00" )
1000 		PORT_DIPSETTING( 0x1c00, "1C00" )
1001 		PORT_DIPSETTING( 0x1d00, "1D00" )
1002 		PORT_DIPSETTING( 0x1e00, "1E00" )
1003 		PORT_DIPSETTING( 0x1f00, "1F00" )
1004 
1005 	PORT_START( "HFDCDIP" )
1006 	PORT_DIPNAME( 0x0c, 0x08, "HFDC drive 1 config" )
1007 		PORT_DIPSETTING( 0x00, "40 track, 16 ms")
1008 		PORT_DIPSETTING( 0x08, "40 track, 8 ms")
1009 		PORT_DIPSETTING( 0x04, "80 track, 2 ms")
1010 		PORT_DIPSETTING( 0x0c, "80 track HD, 2 ms")
1011 	PORT_DIPNAME( 0x03, 0x02, "HFDC drive 2 config" )
1012 		PORT_DIPSETTING( 0x00, "40 track, 16 ms")
1013 		PORT_DIPSETTING( 0x02, "40 track, 8 ms")
1014 		PORT_DIPSETTING( 0x01, "80 track, 2 ms")
1015 		PORT_DIPSETTING( 0x03, "80 track HD, 2 ms")
1016 	PORT_DIPNAME( 0xc0, 0x80, "HFDC drive 3 config" )
1017 		PORT_DIPSETTING( 0x00, "40 track, 16 ms")
1018 		PORT_DIPSETTING( 0x80, "40 track, 8 ms")
1019 		PORT_DIPSETTING( 0x40, "80 track, 2 ms")
1020 		PORT_DIPSETTING( 0xc0, "80 track HD, 2 ms")
1021 	PORT_DIPNAME( 0x30, 0x20, "HFDC drive 4 config" )
1022 		PORT_DIPSETTING( 0x00, "40 track, 16 ms")
1023 		PORT_DIPSETTING( 0x20, "40 track, 8 ms")
1024 		PORT_DIPSETTING( 0x10, "80 track, 2 ms")
1025 		PORT_DIPSETTING( 0x30, "80 track HD, 2 ms")
1026 INPUT_PORTS_END
1027 
1028 FLOPPY_FORMATS_MEMBER(myarc_hfdc_device::floppy_formats)
1029 	FLOPPY_TI99_SDF_FORMAT,
1030 	FLOPPY_TI99_TDF_FORMAT
1031 FLOPPY_FORMATS_END
1032 
1033 static void hfdc_floppies(device_slot_interface &device)
1034 {
1035 	device.option_add("525dd", FLOPPY_525_DD);        // 40 tracks
1036 	device.option_add("525qd", FLOPPY_525_QD);        // 80 tracks
1037 	device.option_add("35dd", FLOPPY_35_DD);          // 80 tracks
1038 	device.option_add("35hd", FLOPPY_35_HD);          // 80 tracks 1.4 MiB
1039 }
1040 
hfdc_harddisks(device_slot_interface & device)1041 static void hfdc_harddisks(device_slot_interface &device)
1042 {
1043 	device.option_add("generic", MFMHD_GENERIC);      // Generic hard disk (self-adapting to image)
1044 	device.option_add("st213", MFMHD_ST213);          // Seagate ST-213 (10 MB)
1045 	device.option_add("st225", MFMHD_ST225);          // Seagate ST-225 (20 MB)
1046 	device.option_add("st251", MFMHD_ST251);          // Seagate ST-251 (40 MB)
1047 }
1048 
1049 ROM_START( ti99_hfdc )
1050 	ROM_REGION(0x4000, TI99_DSRROM, 0)
1051 	ROM_LOAD("hfdc_dsr.u34", 0x0000, 0x4000, CRC(66fbe0ed) SHA1(11df2ecef51de6f543e4eaf8b2529d3e65d0bd59)) /* HFDC disk DSR ROM */
1052 ROM_END
1053 
1054 
device_add_mconfig(machine_config & config)1055 void myarc_hfdc_device::device_add_mconfig(machine_config& config)
1056 {
1057 	HDC9234(config, m_hdc9234, 0);
1058 	m_hdc9234->intrq_cb().set(FUNC(myarc_hfdc_device::intrq_w));
1059 	m_hdc9234->dmarq_cb().set(FUNC(myarc_hfdc_device::dmarq_w));
1060 	m_hdc9234->dip_cb().set(FUNC(myarc_hfdc_device::dip_w));
1061 	m_hdc9234->auxbus_cb().set(FUNC(myarc_hfdc_device::auxbus_out));
1062 	m_hdc9234->dmain_cb().set(FUNC(myarc_hfdc_device::read_buffer));
1063 	m_hdc9234->dmaout_cb().set(FUNC(myarc_hfdc_device::write_buffer));
1064 
1065 	// First two floppy drives shall be connected by default
1066 	FLOPPY_CONNECTOR(config, "f1", hfdc_floppies, "525dd", myarc_hfdc_device::floppy_formats).enable_sound(true);
1067 	FLOPPY_CONNECTOR(config, "f2", hfdc_floppies, "525dd", myarc_hfdc_device::floppy_formats).enable_sound(true);
1068 	FLOPPY_CONNECTOR(config, "f3", hfdc_floppies, nullptr, myarc_hfdc_device::floppy_formats).enable_sound(true);
1069 	FLOPPY_CONNECTOR(config, "f4", hfdc_floppies, nullptr, myarc_hfdc_device::floppy_formats).enable_sound(true);
1070 
1071 	// Hard disks don't go without image (other than floppy drives)
1072 	MFM_HD_CONNECTOR(config, "h1", hfdc_harddisks, nullptr, MFM_BYTE, 3000, 20, MFMHD_GEN_FORMAT);
1073 	MFM_HD_CONNECTOR(config, "h2", hfdc_harddisks, nullptr, MFM_BYTE, 3000, 20, MFMHD_GEN_FORMAT);
1074 	MFM_HD_CONNECTOR(config, "h3", hfdc_harddisks, nullptr, MFM_BYTE, 3000, 20, MFMHD_GEN_FORMAT);
1075 
1076 	MM58274C(config, CLOCK_TAG, 0).set_mode_and_day(1, 0); // 24h, sunday
1077 
1078 	RAM(config, BUFFER).set_default_size("32K").set_default_value(0);
1079 }
1080 
device_rom_region() const1081 const tiny_rom_entry *myarc_hfdc_device::device_rom_region() const
1082 {
1083 	return ROM_NAME( ti99_hfdc );
1084 }
1085 
device_input_ports() const1086 ioport_constructor myarc_hfdc_device::device_input_ports() const
1087 {
1088 	return INPUT_PORTS_NAME( ti99_hfdc );
1089 }
1090 
1091 } } } // end namespace bus::ti99::peb
1092