summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/f4702.cpp
blob: 2a6bf7218c8678e0044d4d8c11281a10300f043c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
// license:BSD-3-Clause
// copyright-holders:AJR
/****************************************************************************

    Fairchild 4702B Programmable Bit Rate Generator

    Originally numbered 34702 in Fairchild's isoplanar CMOS series (whose
    lower-numbered products were logical equivalents of RCA CD4000 and
    Motorola MC14500 series devices), this BRG incorporates some unusually
    sophisticated features into its 16-pin package, which may be why
    Fairchild classified it as a LSI IC.

    The standard 2.4576 MHz master clock, either generated from a crystal
    oscillator (Ix, Ox) or provided as a TTL input (CP), is first prescaled
    by dividing by 8 and then divided further down through a network of
    counters with differing periods. These counters are tapped at 13 points,
    each frequency being 16 times a common baud rate. The rate output (Z),
    whose changes are synchronized with the master clock, is multiplexed
    from any one of these internal sources or an external rate input (Im) by
    a 4-bit select code (S0, S1, S2, S3).

    The buffered clock output (CO) and the three prescaler divisions (Q0,
    Q1, Q2) are not only conveniently available externally for clocking
    additional 4702s or other devices, but can also be exploited to
    generate 8 baud rates simultaneously, with the aid of a Fairchild 93L34
    (or compatible) addressable latch for demultiplexing the channels. In
    this configuration, the CO, Q and Z outputs are respectively tied to the
    latch's enable, address and data inputs, and the Q outputs are directly
    or indirectly fed back into the S inputs. (Fairchild even suggested
    scanning 9LS170 register files with the Q outputs so as to make each
    rate individually programmable.)

    The rate select codes are arranged so that connecting a simple five-
    point switch to the S inputs can obtain 110, 150, 300, 1200 or 2400
    baud, and only three binary switches are needed to select between all
    five of those rates plus 1800, 4800 and 9600 baud. 19200 baud can also
    be obtained by tapping the Q2 output, but no more than 4 internally
    multiplexed rates can be used at once if Im is generated from Q2.

    All inputs and outputs except Ix and Ox are TTL-compatible, with the
    inputs also having internal pull-ups so switches can be connected
    directly.

    To enable the Ix/Ox oscillator circuit, Ecp must be high and CP must
    remain low, since Ecp and CP both being high places the chip in a
    continuous reset mode (except for the CO output). If Ecp is brought
    low, the initialization circuit produces an internal master reset
    pulse the first time CP goes high. Neither of these two reset methods
    was used much in practice.

    Intersil, one of not many companies to second-source the original 4702,
    later produced IM4712, a minor variant which requires fewer external
    discrete components to drive the crystal oscillator but is otherwise
    logically identical.

****************************************************************************/

#include "emu.h"
#include "machine/f4702.h"


//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

// device type definition
DEFINE_DEVICE_TYPE(F4702, f4702_device, "f4702", "Fairchild 4702B Bit Rate Generator")


//**************************************************************************
//  DEVICE CONSTRUCTION AND INITIALIZATION
//**************************************************************************

//-------------------------------------------------
//  f4702_device - constructor
//-------------------------------------------------

f4702_device::f4702_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
	: device_t(mconfig, F4702, tag, owner, clock)
	, device_execute_interface(mconfig, *this)
	, m_s_callback(*this)
	, m_z_callback(*this)
	, m_main_counter(0)
	, m_div_200_50(0)
	, m_div_134_5(0)
	, m_div_110(0)
	, m_div_1800(0)
	, m_im(true)
	, m_s(0)
	, m_icount(0)
{
}


//-------------------------------------------------
//  device_resolve_objects - resolve objects that
//  may be needed for other devices to set
//  initial conditions at start time
//-------------------------------------------------

void f4702_device::device_resolve_objects()
{
	// resolve callbacks
	m_s_callback.resolve_safe(15);
	m_z_callback.resolve_safe();
}


//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void f4702_device::device_start()
{
	set_icountptr(m_icount);

	save_item(NAME(m_main_counter));
	save_item(NAME(m_div_200_50));
	save_item(NAME(m_div_134_5));
	save_item(NAME(m_div_110));
	save_item(NAME(m_div_1800));
	save_item(NAME(m_im));
	save_item(NAME(m_s));
}


//-------------------------------------------------
//  reset_counters - optional master reset
//-------------------------------------------------

void f4702_device::reset_counters()
{
	// Reset counter network
	m_main_counter = 0;
	m_div_200_50 = 0;
	m_div_134_5 = 0;
	m_div_1800 = 0;

	// Reset Q and Z outputs
	m_z_callback(0, 0);
}


//**************************************************************************
//  RATE GENERATION
//**************************************************************************

//-------------------------------------------------
//  im_w - set external rate input
//-------------------------------------------------

WRITE_LINE_MEMBER(f4702_device::im_w)
{
	m_im = state;
}


//-------------------------------------------------
//  z_output - recalculate output state
//-------------------------------------------------

bool f4702_device::z_output() const
{
	// Select Z output from one of the 13 counter taps or the external input
	switch (m_s)
	{
	// S3–S0 = LLLL or LLLH: multiplexed input
	case 0:
	case 1:
	default:
		return m_im;

	// S3–S0 = LLHL: 50 baud
	case 2:
		return m_div_200_50 >= 12;

	// S3–S0 = LLHH: 75 baud
	case 3:
		return BIT(m_main_counter, 10);

	// S3–S0 = LHLL: 134.5 baud (-0.87% error)
	case 4:
		return m_div_134_5 >= 9;

	// S3–S0 = LHLH: 200 baud
	case 5:
		return (m_div_200_50 % 6) >= 3;

	// S3–S0 = LHHL: 600 baud
	case 6:
		return BIT(m_main_counter, 7);

	// S3–S0 = LHHH or HHLL: 2400 baud
	case 7:
	case 12:
		return BIT(m_main_counter, 5);

	// S3–S0 = HLLL: 9600 baud
	case 8:
		return BIT(m_main_counter, 3);

	// S3–S0 = HLLH: 4800 baud
	case 9:
		return BIT(m_main_counter, 4);

	// S3–S0 = HLHL: 1800 baud
	case 10:
		return (m_div_1800 % 5) >= 2;

	// S3–S0 = HLHH: 1200 baud
	case 11:
		return BIT(m_main_counter, 6);

	// S3–S0 = HHLH: 300 baud
	case 13:
		return BIT(m_main_counter, 8);

	// S3–S0 = HHHL: 150 baud
	case 14:
		return BIT(m_main_counter, 9);

	// S3–S0 = HHHH: 110 baud (-0.83% error)
	case 15:
		return m_div_110 >= 11;
	}
}


//-------------------------------------------------
//  execute_run - execute a timeslice's worth of
//  counting
//-------------------------------------------------

void f4702_device::execute_run()
{
	do {
		// Drive the main scan and frequency counter
		m_main_counter++;
		if ((m_main_counter & 0x00f) == 0)
		{
			// Divide 9600 baud by 16/3 (16 = 5 + 5 + 6)
			m_div_1800++;
			if (m_div_1800 >= 16)
				m_div_1800 = 0;

			if ((m_main_counter & 0x03f) == 0)
			{
				// Divide 2400 baud by 18
				m_div_134_5++;
				if (m_div_134_5 >= 18)
					m_div_134_5 = 0;

				// Divide 2400 baud by 22 as well
				m_div_110++;
				if (m_div_110 >= 22)
					m_div_110 = 0;

				if ((m_main_counter & 0x07f) == 0)
				{
					// Divide 1200 baud by 6 and then again by 4
					m_div_200_50++;
					if (m_div_200_50 >= 24)
						m_div_200_50 = 0;
				}
			}
		}

		// Update Q and Z outputs
		m_z_callback(m_main_counter & 0x007, z_output());

		// S3–S0 inputs are valid on the rising edge of CO
		m_s = m_s_callback(m_main_counter & 0x007) & 15;
	} while (--m_icount > 0);
}