1 // license:BSD-3-Clause
2 // copyright-holders:Olivier Galibert
3 #include "emu.h"
4 #include "fdc_pll.h"
5 #include "imagedev/floppy.h"
6 
tts(attotime t)7 std::string fdc_pll_t::tts(attotime t)
8 {
9 	char buf[256];
10 	bool neg = t.seconds() < 0;
11 	if(neg)
12 		t = attotime::zero - t;
13 	int nsec = t.attoseconds() / ATTOSECONDS_PER_NANOSECOND;
14 	sprintf(buf, "%c%3d.%03d,%03d,%03d", neg ? '-' : ' ', int(t.seconds()), nsec/1000000, (nsec/1000)%1000, nsec % 1000);
15 	return buf;
16 }
17 
set_clock(const attotime & _period)18 void fdc_pll_t::set_clock(const attotime &_period)
19 {
20 	period = _period;
21 	double period_as_double = period.as_double();
22 	period_adjust_base = attotime::from_double(period_as_double * 0.05);
23 	min_period = attotime::from_double(period_as_double * 0.75);
24 	max_period = attotime::from_double(period_as_double * 1.25);
25 }
26 
reset(const attotime & when)27 void fdc_pll_t::reset(const attotime &when)
28 {
29 	read_reset(when);
30 	write_position = 0;
31 	write_start_time = attotime::never;
32 }
33 
read_reset(const attotime & when)34 void fdc_pll_t::read_reset(const attotime &when)
35 {
36 	ctime = when;
37 	phase_adjust = attotime::zero;
38 	freq_hist = 0;
39 }
40 
start_writing(const attotime & tm)41 void fdc_pll_t::start_writing(const attotime &tm)
42 {
43 	write_start_time = tm;
44 	write_position = 0;
45 }
46 
stop_writing(floppy_image_device * floppy,const attotime & tm)47 void fdc_pll_t::stop_writing(floppy_image_device *floppy, const attotime &tm)
48 {
49 	commit(floppy, tm);
50 	write_start_time = attotime::never;
51 }
52 
commit(floppy_image_device * floppy,const attotime & tm)53 void fdc_pll_t::commit(floppy_image_device *floppy, const attotime &tm)
54 {
55 	if(write_start_time.is_never() || tm == write_start_time)
56 		return;
57 
58 	if(floppy)
59 		floppy->write_flux(write_start_time, tm, write_position, write_buffer);
60 	write_start_time = tm;
61 	write_position = 0;
62 }
63 
get_next_bit(attotime & tm,floppy_image_device * floppy,const attotime & limit)64 int fdc_pll_t::get_next_bit(attotime &tm, floppy_image_device *floppy, const attotime &limit)
65 {
66 	attotime edge = floppy ? floppy->get_next_transition(ctime) : attotime::never;
67 
68 	return feed_read_data(tm , edge , limit);
69 }
70 
feed_read_data(attotime & tm,const attotime & edge,const attotime & limit)71 int fdc_pll_t::feed_read_data(attotime &tm, const attotime& edge, const attotime &limit)
72 {
73 	attotime next = ctime + period + phase_adjust;
74 
75 #if 0
76 	if(!edge.is_never())
77 		fprintf(stderr, "ctime=%s, transition_time=%s, next=%s, pha=%s\n", tts(ctime).c_str(), tts(edge).c_str(), tts(next).c_str(), tts(phase_adjust).c_str());
78 #endif
79 
80 	if(next > limit)
81 		return -1;
82 
83 	ctime = next;
84 	tm = next;
85 
86 	if(edge.is_never() || edge > next) {
87 		// No transition in the window means 0 and pll in free run mode
88 		phase_adjust = attotime::zero;
89 		return 0;
90 	}
91 
92 	// Transition in the window means 1, and the pll is adjusted
93 
94 	attotime delta = edge - (next - period/2);
95 
96 	if(delta.seconds() < 0)
97 		phase_adjust = attotime::zero - ((attotime::zero - delta)*65)/100;
98 	else
99 		phase_adjust = (delta*65)/100;
100 
101 	if(delta < attotime::zero) {
102 		if(freq_hist < 0)
103 			freq_hist--;
104 		else
105 			freq_hist = -1;
106 	} else if(delta > attotime::zero) {
107 		if(freq_hist > 0)
108 			freq_hist++;
109 		else
110 			freq_hist = 1;
111 	} else
112 		freq_hist = 0;
113 
114 	if(freq_hist) {
115 		int afh = freq_hist < 0 ? -freq_hist : freq_hist;
116 		if(afh > 1) {
117 			attotime aper = attotime::from_double(period_adjust_base.as_double()*delta.as_double()/period.as_double());
118 			period += aper;
119 
120 			if(period < min_period)
121 				period = min_period;
122 			else if(period > max_period)
123 				period = max_period;
124 		}
125 	}
126 
127 	return 1;
128 }
129 
write_next_bit(bool bit,attotime & tm,floppy_image_device * floppy,const attotime & limit)130 bool fdc_pll_t::write_next_bit(bool bit, attotime &tm, floppy_image_device *floppy, const attotime &limit)
131 {
132 	if(write_start_time.is_never()) {
133 		write_start_time = ctime;
134 		write_position = 0;
135 	}
136 
137 	attotime etime = ctime + period;
138 	if(etime > limit)
139 		return true;
140 
141 	if(bit && write_position < ARRAY_LENGTH(write_buffer))
142 		write_buffer[write_position++] = ctime + period/2;
143 
144 	tm = etime;
145 	ctime = etime;
146 	return false;
147 }
148