1 // license:BSD-3-Clause
2 // copyright-holders:Olivier Galibert
3 /***************************************************************************
4 
5     Amiga floppy disk controller emulation
6 
7 ***************************************************************************/
8 
9 
10 #include "emu.h"
11 #include "formats/ami_dsk.h"
12 #include "amigafdc.h"
13 
14 DEFINE_DEVICE_TYPE(AMIGA_FDC, amiga_fdc_device, "amiga_fdc", "Amiga FDC")
15 
FLOPPY_FORMATS_MEMBER(amiga_fdc_device::floppy_formats)16 FLOPPY_FORMATS_MEMBER( amiga_fdc_device::floppy_formats )
17 	FLOPPY_ADF_FORMAT
18 FLOPPY_FORMATS_END
19 
20 amiga_fdc_device::amiga_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
21 	device_t(mconfig, AMIGA_FDC, tag, owner, clock),
22 	m_write_index(*this),
23 	m_read_dma(*this),
24 	m_write_dma(*this),
25 	m_write_dskblk(*this),
26 	m_write_dsksyn(*this),
27 	m_leds(*this, "led%u", 1U),
28 	m_fdc_led(*this, "fdc_led"),
29 	floppy(nullptr), t_gen(nullptr), dsklen(0), pre_dsklen(0), dsksync(0), dskbyt(0), adkcon(0), dmacon(0), dskpt(0), dma_value(0), dma_state(0)
30 {
31 }
32 
device_start()33 void amiga_fdc_device::device_start()
34 {
35 	m_write_index.resolve_safe();
36 	m_read_dma.resolve_safe(0);
37 	m_write_dma.resolve_safe();
38 	m_write_dskblk.resolve_safe();
39 	m_write_dsksyn.resolve_safe();
40 	m_leds.resolve();
41 	m_fdc_led.resolve();
42 
43 	static char const *const names[] = { "0", "1", "2", "3" };
44 	for(int i=0; i != 4; i++) {
45 		floppy_connector *con = subdevice<floppy_connector>(names[i]);
46 		if(con)
47 			floppy_devices[i] = con->get_device();
48 		else
49 			floppy_devices[i] = nullptr;
50 	}
51 
52 	floppy = nullptr;
53 
54 	t_gen = timer_alloc(0);
55 }
56 
57 
device_reset()58 void amiga_fdc_device::device_reset()
59 {
60 	floppy = nullptr;
61 	dsklen = 0x4000;
62 	dsksync = 0x4489;
63 	adkcon = 0;
64 	dmacon = 0;
65 	dskpt = 0;
66 	dskbyt = 0;
67 	pre_dsklen = 0x4000;
68 	dma_value = 0;
69 	dma_state = DMA_IDLE;
70 
71 	live_abort();
72 }
73 
dma_done()74 void amiga_fdc_device::dma_done()
75 {
76 	if(dskbyt & 0x2000) {
77 		dskbyt &= ~0x2000;
78 		cur_live.pll.stop_writing(floppy, cur_live.tm);
79 	}
80 
81 	dma_state = DMA_IDLE;
82 	m_write_dskblk(1);
83 }
84 
dma_write(uint16_t value)85 void amiga_fdc_device::dma_write(uint16_t value)
86 {
87 	m_write_dma(dskpt, value, 0xffff);
88 
89 	dskpt += 2;
90 	dsklen--;
91 
92 	if(dsklen & 0x3fff)
93 		dma_state = DMA_RUNNING_BYTE_0;
94 	else
95 		dma_done();
96 }
97 
dma_read()98 uint16_t amiga_fdc_device::dma_read()
99 {
100 	uint16_t res = m_read_dma(dskpt, 0xffff);
101 
102 	dskpt += 2;
103 	dsklen--;
104 
105 	// This loses the last word.  So does the real hardware.
106 	if(dsklen & 0x3fff)
107 		dma_state = DMA_RUNNING_BYTE_0;
108 	else
109 		dma_done();
110 
111 	return res;
112 }
113 
live_start()114 void amiga_fdc_device::live_start()
115 {
116 	cur_live.tm = machine().time();
117 	cur_live.state = RUNNING;
118 	cur_live.next_state = -1;
119 	cur_live.shift_reg = 0;
120 	cur_live.bit_counter = 0;
121 	cur_live.pll.reset(cur_live.tm);
122 	cur_live.pll.set_clock(clocks_to_attotime(1));
123 	checkpoint_live = cur_live;
124 
125 	live_run();
126 }
127 
checkpoint()128 void amiga_fdc_device::checkpoint()
129 {
130 	cur_live.pll.commit(floppy, cur_live.tm);
131 	checkpoint_live = cur_live;
132 }
133 
rollback()134 void amiga_fdc_device::rollback()
135 {
136 	cur_live = checkpoint_live;
137 }
138 
live_delay(int state)139 void amiga_fdc_device::live_delay(int state)
140 {
141 	cur_live.next_state = state;
142 	if(cur_live.tm != machine().time())
143 		t_gen->adjust(cur_live.tm - machine().time());
144 }
145 
live_sync()146 void amiga_fdc_device::live_sync()
147 {
148 	if(!cur_live.tm.is_never()) {
149 		if(cur_live.tm > machine().time()) {
150 			rollback();
151 			live_run(machine().time());
152 			cur_live.pll.commit(floppy, cur_live.tm);
153 
154 		} else {
155 			cur_live.pll.commit(floppy, cur_live.tm);
156 
157 			if(cur_live.next_state != -1) {
158 				cur_live.state = cur_live.next_state;
159 				cur_live.next_state = -1;
160 			}
161 			if(cur_live.state == IDLE) {
162 				cur_live.pll.stop_writing(floppy, cur_live.tm);
163 				cur_live.tm = attotime::never;
164 			}
165 		}
166 		cur_live.next_state = -1;
167 		checkpoint();
168 	}
169 }
170 
live_abort()171 void amiga_fdc_device::live_abort()
172 {
173 	if(!cur_live.tm.is_never() && cur_live.tm > machine().time()) {
174 		rollback();
175 		live_run(machine().time());
176 	}
177 
178 	cur_live.pll.stop_writing(floppy, cur_live.tm);
179 	cur_live.tm = attotime::never;
180 	cur_live.state = IDLE;
181 	cur_live.next_state = -1;
182 }
183 
live_run(const attotime & limit)184 void amiga_fdc_device::live_run(const attotime &limit)
185 {
186 	if(cur_live.state == IDLE || cur_live.next_state != -1)
187 		return;
188 
189 	for(;;) {
190 		switch(cur_live.state) {
191 		case RUNNING: {
192 			if(!(dskbyt & 0x2000)) {
193 				int bit = cur_live.pll.get_next_bit(cur_live.tm, floppy, limit);
194 				if(bit < 0)
195 					return;
196 
197 				cur_live.shift_reg = (cur_live.shift_reg << 1) | bit;
198 				cur_live.bit_counter++;
199 
200 				if((adkcon & 0x0200) && !(cur_live.shift_reg & 0x80)) {
201 					cur_live.bit_counter--;
202 
203 					// Avoid any risk of livelock
204 					live_delay(RUNNING_SYNCPOINT);
205 					return;
206 				}
207 
208 				if(cur_live.bit_counter > 8)
209 					fatalerror("amiga_fdc_device::live_run - cur_live.bit_counter > 8\n");
210 
211 				if(cur_live.bit_counter == 8) {
212 					live_delay(RUNNING_SYNCPOINT);
213 					return;
214 				}
215 				if(dskbyt & 0x1000) {
216 					if(cur_live.shift_reg != dsksync) {
217 						live_delay(RUNNING_SYNCPOINT);
218 						return;
219 					}
220 				} else {
221 					if(cur_live.shift_reg == dsksync) {
222 						live_delay(RUNNING_SYNCPOINT);
223 						return;
224 					}
225 				}
226 			} else {
227 				int bit = (dma_state == DMA_RUNNING_BYTE_0 ? 15 : 7) - cur_live.bit_counter;
228 				if(cur_live.pll.write_next_bit((dma_value >> bit) & 1, cur_live.tm, floppy, limit))
229 					return;
230 				cur_live.bit_counter++;
231 				if(cur_live.bit_counter > 8)
232 					fatalerror("amiga_fdc_device::live_run - cur_live.bit_counter > 8\n");
233 
234 				if(cur_live.bit_counter == 8) {
235 					live_delay(RUNNING_SYNCPOINT);
236 					return;
237 				}
238 			}
239 			break;
240 		}
241 
242 		case RUNNING_SYNCPOINT: {
243 			if(!(dskbyt & 0x2000)) {
244 				if(cur_live.shift_reg == dsksync) {
245 					if(adkcon & 0x0400) {
246 						if(dma_state == DMA_WAIT_START) {
247 							cur_live.bit_counter = 0;
248 
249 							if(!(dsklen & 0x3fff))
250 								dma_done();
251 							else if(dsklen & 0x4000) {
252 								dskbyt |= 0x2000;
253 								cur_live.bit_counter = 0;
254 								dma_value = dma_read();
255 
256 							} else
257 								dma_write(dsksync);
258 
259 						} else if(dma_state != DMA_IDLE) {
260 							dma_write(dsksync);
261 							cur_live.bit_counter = 0;
262 
263 						} else if(cur_live.bit_counter != 8)
264 							cur_live.bit_counter = 0;
265 					}
266 					dskbyt |= 0x1000;
267 					m_write_dsksyn(1);
268 				} else
269 					dskbyt &= ~0x1000;
270 
271 				if(cur_live.bit_counter == 8) {
272 					dskbyt = (dskbyt & 0xff00) | 0x8000 | (cur_live.shift_reg & 0xff);
273 					cur_live.bit_counter = 0;
274 
275 					switch(dma_state) {
276 					case DMA_IDLE:
277 					case DMA_WAIT_START:
278 						break;
279 
280 					case DMA_RUNNING_BYTE_0:
281 						dma_value = (cur_live.shift_reg & 0xff) << 8;
282 						dma_state = DMA_RUNNING_BYTE_1;
283 						break;
284 
285 					case DMA_RUNNING_BYTE_1: {
286 						dma_value |= cur_live.shift_reg & 0xff;
287 						dma_write(dma_value);
288 						break;
289 					}
290 					}
291 				}
292 			} else {
293 				if(cur_live.bit_counter != 8)
294 					fatalerror("amiga_fdc_device::live_run - cur_live.bit_counter != 8\n");
295 				cur_live.bit_counter = 0;
296 
297 				switch(dma_state) {
298 				case DMA_IDLE:
299 				case DMA_WAIT_START:
300 					break;
301 
302 				case DMA_RUNNING_BYTE_0:
303 					dma_state = DMA_RUNNING_BYTE_1;
304 					break;
305 
306 				case DMA_RUNNING_BYTE_1: {
307 					dma_value = dma_read();
308 					break;
309 				}
310 				}
311 			}
312 
313 			cur_live.state = RUNNING;
314 			checkpoint();
315 			break;
316 		}
317 		}
318 	}
319 }
320 
dma_enabled()321 bool amiga_fdc_device::dma_enabled()
322 {
323 	return (dsklen & 0x8000) && ((dmacon & 0x0210) == 0x0210);
324 }
325 
dma_check()326 void amiga_fdc_device::dma_check()
327 {
328 	bool was_writing = dskbyt & 0x2000;
329 	dskbyt &= 0x9fff;
330 	if(dma_enabled()) {
331 		if(dma_state == IDLE) {
332 			dma_state = adkcon & 0x0400 ? DMA_WAIT_START : DMA_RUNNING_BYTE_0;
333 			if(dma_state == DMA_RUNNING_BYTE_0) {
334 				if(!(dsklen & 0x3fff))
335 					dma_done();
336 				else if(dsklen & 0x4000) {
337 					dskbyt |= 0x2000;
338 					cur_live.bit_counter = 0;
339 					dma_value = dma_read();
340 				}
341 			}
342 		} else {
343 			dskbyt |= 0x4000;
344 			if(dsklen & 0x4000)
345 				dskbyt |= 0x2000;
346 		}
347 	} else
348 		dma_state = IDLE;
349 
350 	if(was_writing && !(dskbyt & 0x2000))
351 		cur_live.pll.stop_writing(floppy, cur_live.tm);
352 	if(!was_writing && (dskbyt & 0x2000))
353 		cur_live.pll.start_writing(cur_live.tm);
354 
355 }
356 
adkcon_set(uint16_t data)357 void amiga_fdc_device::adkcon_set(uint16_t data)
358 {
359 	live_sync();
360 	adkcon = data;
361 	live_run();
362 }
363 
adkcon_r(void)364 uint16_t amiga_fdc_device::adkcon_r(void)
365 {
366 	return adkcon;
367 }
368 
dsklen_w(uint16_t data)369 void amiga_fdc_device::dsklen_w(uint16_t data)
370 {
371 	live_sync();
372 	if(!(data & 0x8000) || (data == pre_dsklen)) {
373 		dsklen = pre_dsklen = data;
374 		dma_check();
375 
376 	} else
377 		pre_dsklen = data;
378 	live_run();
379 }
380 
dskpth_w(uint16_t data)381 void amiga_fdc_device::dskpth_w(uint16_t data)
382 {
383 	live_sync();
384 	dskpt = (dskpt & 0xffff) | (data << 16);
385 	live_run();
386 }
387 
dskptl_w(uint16_t data)388 void amiga_fdc_device::dskptl_w(uint16_t data)
389 {
390 	live_sync();
391 	dskpt = (dskpt & 0xffff0000) | data;
392 	live_run();
393 }
394 
dskpth_r()395 uint16_t amiga_fdc_device::dskpth_r()
396 {
397 	return dskpt >> 16;
398 }
399 
dskptl_r()400 uint16_t amiga_fdc_device::dskptl_r()
401 {
402 	return dskpt;
403 }
404 
dsksync_w(uint16_t data)405 void amiga_fdc_device::dsksync_w(uint16_t data)
406 {
407 	live_sync();
408 	dsksync = data;
409 	live_run();
410 }
411 
dmacon_set(uint16_t data)412 void amiga_fdc_device::dmacon_set(uint16_t data)
413 {
414 	live_sync();
415 	dmacon = data;
416 	dma_check();
417 	live_run();
418 }
419 
dskbytr_r()420 uint16_t amiga_fdc_device::dskbytr_r()
421 {
422 	uint16_t res = dskbyt;
423 	dskbyt &= 0x7fff;
424 	return res;
425 }
426 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)427 void amiga_fdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
428 {
429 	live_sync();
430 	live_run();
431 }
432 
setup_leds()433 void amiga_fdc_device::setup_leds()
434 {
435 	if(floppy) {
436 		int drive =
437 			floppy == floppy_devices[0] ? 0 :
438 			floppy == floppy_devices[1] ? 1 :
439 			floppy == floppy_devices[2] ? 2 :
440 			3;
441 
442 		m_leds[0] = drive == 0 ? 1 : 0; // update internal drive led
443 		m_leds[1] = drive == 1 ? 1 : 0;  // update external drive led
444 	}
445 }
446 
ciaaprb_w(uint8_t data)447 void amiga_fdc_device::ciaaprb_w(uint8_t data)
448 {
449 	floppy_image_device *old_floppy = floppy;
450 
451 	live_sync();
452 
453 	if(!(data & 0x08))
454 		floppy = floppy_devices[0];
455 	else if(!(data & 0x10))
456 		floppy = floppy_devices[1];
457 	else if(!(data & 0x20))
458 		floppy = floppy_devices[2];
459 	else if(!(data & 0x40))
460 		floppy = floppy_devices[3];
461 	else
462 		floppy = nullptr;
463 
464 	if(old_floppy != floppy) {
465 		if(old_floppy)
466 			old_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb());
467 		if(floppy)
468 			floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(&amiga_fdc_device::index_callback, this));
469 	}
470 
471 	if(floppy) {
472 		floppy->ss_w(!(BIT(data, 2)));
473 		floppy->dir_w(BIT(data, 1));
474 		floppy->stp_w(BIT(data, 0));
475 		floppy->mon_w(BIT(data, 7));
476 		m_fdc_led = BIT(data, 7); // LED directly connected to FDC motor
477 	}
478 
479 	if(floppy) {
480 		if(cur_live.state == IDLE)
481 			live_start();
482 	} else
483 		live_abort();
484 
485 	setup_leds();
486 	live_run();
487 }
488 
ciaapra_r()489 uint8_t amiga_fdc_device::ciaapra_r()
490 {
491 	uint8_t ret = 0x3c;
492 	if(floppy) {
493 		//if(!floppy->ready_r()) fixit: seems to not work well with multiple disk drives
494 			ret &= ~0x20;
495 		if(!floppy->trk00_r())
496 			ret &= ~0x10;
497 		if(floppy->wpt_r())
498 			ret &= ~0x08;
499 		if(!floppy->dskchg_r())
500 			ret &= ~0x04;
501 	}
502 
503 	return ret;
504 }
505 
index_callback(floppy_image_device * floppy,int state)506 void amiga_fdc_device::index_callback(floppy_image_device *floppy, int state)
507 {
508 	/* Issue a index pulse when a disk revolution completes */
509 	m_write_index(!state);
510 }
511 
set_clock(const attotime & period)512 void amiga_fdc_device::pll_t::set_clock(const attotime &period)
513 {
514 	for(int i=0; i<38; i++)
515 		delays[i] = period*(i+1);
516 }
517 
reset(const attotime & when)518 void amiga_fdc_device::pll_t::reset(const attotime &when)
519 {
520 	counter = 0;
521 	increment = 146;
522 	transition_time = 0xffff;
523 	history = 0x80;
524 	slot = 0;
525 	ctime = when;
526 	phase_add = 0x00;
527 	phase_sub = 0x00;
528 	freq_add  = 0x00;
529 	freq_sub  = 0x00;
530 }
531 
get_next_bit(attotime & tm,floppy_image_device * floppy,const attotime & limit)532 int amiga_fdc_device::pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit)
533 {
534 	attotime when = floppy ? floppy->get_next_transition(ctime) : attotime::never;
535 
536 	for(;;) {
537 		attotime etime = ctime+delays[slot];
538 		if(etime > limit)
539 			return -1;
540 		if(transition_time == 0xffff && !when.is_never() && etime >= when)
541 			transition_time = counter;
542 		if(slot < 8) {
543 			uint8_t mask = 1 << slot;
544 			if(phase_add & mask)
545 				counter += 258;
546 			else if(phase_sub & mask)
547 				counter += 34;
548 			else
549 				counter += increment;
550 
551 			if((freq_add & mask) && increment < 159)
552 				increment++;
553 			else if((freq_sub & mask) && increment > 134)
554 				increment--;
555 		} else
556 			counter += increment;
557 
558 		slot++;
559 		tm = etime;
560 		if(counter & 0x800)
561 			break;
562 	}
563 
564 	int bit = transition_time != 0xffff;
565 
566 	if(transition_time != 0xffff) {
567 		static uint8_t const pha[8] = { 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 };
568 		static uint8_t const phs[8] = { 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf };
569 		static uint8_t const freqa[4][8] = {
570 			{ 0xf, 0x7, 0x3, 0x1, 0, 0, 0, 0 },
571 			{ 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 },
572 			{ 0x7, 0x3, 0x1, 0, 0, 0, 0, 0 },
573 			{ 0, 0, 0, 0, 0, 0, 0, 0 }
574 		};
575 		static uint8_t const freqs[4][8] = {
576 			{ 0, 0, 0, 0, 0, 0, 0, 0 },
577 			{ 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 },
578 			{ 0, 0, 0, 0, 0, 0x1, 0x3, 0x7 },
579 			{ 0, 0, 0, 0, 0x1, 0x3, 0x7, 0xf },
580 		};
581 
582 		int cslot = transition_time >> 8;
583 		phase_add = pha[cslot];
584 		phase_sub = phs[cslot];
585 		int way = transition_time & 0x400 ? 1 : 0;
586 		if(history & 0x80)
587 			history = way ? 0x80 : 0x83;
588 		else if(history & 0x40)
589 			history = way ? history & 2 : (history & 2) | 1;
590 		freq_add = freqa[history & 3][cslot];
591 		freq_sub = freqs[history & 3][cslot];
592 		history = way ? (history >> 1) | 2 : history >> 1;
593 
594 	} else
595 		phase_add = phase_sub = freq_add = freq_sub = 0;
596 
597 	counter &= 0x7ff;
598 
599 	ctime = tm;
600 	transition_time = 0xffff;
601 	slot = 0;
602 
603 	return bit;
604 }
605 
start_writing(const attotime & tm)606 void amiga_fdc_device::pll_t::start_writing(const attotime & tm)
607 {
608 	write_start_time = tm;
609 	write_position = 0;
610 }
611 
stop_writing(floppy_image_device * floppy,const attotime & tm)612 void amiga_fdc_device::pll_t::stop_writing(floppy_image_device *floppy, const attotime &tm)
613 {
614 	commit(floppy, tm);
615 	write_start_time = attotime::never;
616 }
617 
write_next_bit(bool bit,attotime & tm,floppy_image_device * floppy,const attotime & limit)618 bool amiga_fdc_device::pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit)
619 {
620 	if(write_start_time.is_never()) {
621 		write_start_time = ctime;
622 		write_position = 0;
623 	}
624 
625 	for(;;) {
626 		attotime etime = ctime+delays[slot];
627 		if(etime > limit)
628 			return true;
629 		uint16_t pre_counter = counter;
630 		counter += increment;
631 		if(bit && !(pre_counter & 0x400) && (counter & 0x400))
632 			if(write_position < ARRAY_LENGTH(write_buffer))
633 				write_buffer[write_position++] = etime;
634 		slot++;
635 		tm = etime;
636 		if(counter & 0x800)
637 			break;
638 	}
639 
640 	counter &= 0x7ff;
641 
642 	ctime = tm;
643 	slot = 0;
644 
645 	return false;
646 }
647 
648 
commit(floppy_image_device * floppy,const attotime & tm)649 void amiga_fdc_device::pll_t::commit(floppy_image_device *floppy, const attotime &tm)
650 {
651 	if(write_start_time.is_never() || tm == write_start_time)
652 		return;
653 
654 	if(floppy)
655 		floppy->write_flux(write_start_time, tm, write_position, write_buffer);
656 	write_start_time = tm;
657 	write_position = 0;
658 }
659