1 // license:BSD-3-Clause
2 // copyright-holders:Luca Elia, AJR
3 /***************************************************************************
4 
5     TMP68301 basic emulation + Interrupt Handling
6 
7     The Toshiba TMP68301 is a 68HC000 + serial I/O, parallel I/O,
8     3 timers, address decoder, wait generator, interrupt controller,
9     all integrated in a single chip.
10 
11     TODO:
12     - Interrupt generation: edge detection, input expansion (INT3-INT9)
13     - Parallel port: handle timing latency
14     - Serial port: not done at all
15     - (and many other things)
16 
17 ***************************************************************************/
18 
19 #include "emu.h"
20 #include "machine/tmp68301.h"
21 
22 DEFINE_DEVICE_TYPE(TMP68301, tmp68301_device, "tmp68301", "Toshiba TMP68301")
23 
tmp68301_regs(address_map & map)24 void tmp68301_device::tmp68301_regs(address_map &map)
25 {
26 	map(0x000, 0x3ff).rw(FUNC(tmp68301_device::regs_r), FUNC(tmp68301_device::regs_w));
27 
28 	map(0x080, 0x093).rw(FUNC(tmp68301_device::icr_r), FUNC(tmp68301_device::icr_w)).umask16(0x00ff);
29 
30 	map(0x094, 0x095).rw(FUNC(tmp68301_device::imr_r), FUNC(tmp68301_device::imr_w));
31 	map(0x096, 0x097).rw(FUNC(tmp68301_device::ipr_r), FUNC(tmp68301_device::ipr_w));
32 	map(0x098, 0x099).rw(FUNC(tmp68301_device::iisr_r), FUNC(tmp68301_device::iisr_w));
33 
34 	/* Parallel Port */
35 	map(0x100, 0x101).rw(FUNC(tmp68301_device::pdir_r), FUNC(tmp68301_device::pdir_w));
36 	map(0x10a, 0x10b).rw(FUNC(tmp68301_device::pdr_r), FUNC(tmp68301_device::pdr_w));
37 
38 	/* Serial Port */
39 	map(0x18e, 0x18f).rw(FUNC(tmp68301_device::scr_r), FUNC(tmp68301_device::scr_w));
40 }
41 
42 // IRQ Mask register
imr_r()43 uint16_t tmp68301_device::imr_r()
44 {
45 	return m_imr;
46 }
47 
imr_w(offs_t offset,uint16_t data,uint16_t mem_mask)48 void tmp68301_device::imr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
49 {
50 	COMBINE_DATA(&m_imr);
51 	update_ipl();
52 }
53 
54 // IRQ Pending Register
ipr_r()55 uint16_t tmp68301_device::ipr_r()
56 {
57 	return m_ipr;
58 }
59 
ipr_w(offs_t offset,uint16_t data,uint16_t mem_mask)60 void tmp68301_device::ipr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
61 {
62 	// software writes only clear bits
63 	m_ipr &= data | ~mem_mask;
64 	update_ipl();
65 }
66 
67 // IRQ In-Service Register
iisr_r()68 uint16_t tmp68301_device::iisr_r()
69 {
70 	return m_iisr;
71 }
72 
iisr_w(offs_t offset,uint16_t data,uint16_t mem_mask)73 void tmp68301_device::iisr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
74 {
75 	// software writes only clear bits
76 	m_iisr &= data | ~mem_mask;
77 }
78 
79 // Serial Control Register (TODO: 8-bit wide)
scr_r()80 uint16_t tmp68301_device::scr_r()
81 {
82 	return m_scr;
83 }
84 
scr_w(offs_t offset,uint16_t data,uint16_t mem_mask)85 void tmp68301_device::scr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
86 {
87 	/*
88 	    *--- ---- CKSE
89 	    --*- ---- RES
90 	    ---- ---* INTM
91 	*/
92 
93 	COMBINE_DATA(&m_scr);
94 	m_scr &= 0xa1;
95 }
96 
97 /* Parallel direction: 1 = output, 0 = input */
pdir_r()98 uint16_t tmp68301_device::pdir_r()
99 {
100 	return m_pdir;
101 }
102 
pdir_w(offs_t offset,uint16_t data,uint16_t mem_mask)103 void tmp68301_device::pdir_w(offs_t offset, uint16_t data, uint16_t mem_mask)
104 {
105 	COMBINE_DATA(&m_pdir);
106 }
107 
pdr_r()108 uint16_t tmp68301_device::pdr_r()
109 {
110 	return (m_in_parallel_cb(0) & ~m_pdir) | (m_pdr & m_pdir);
111 }
112 
pdr_w(offs_t offset,uint16_t data,uint16_t mem_mask)113 void tmp68301_device::pdr_w(offs_t offset, uint16_t data, uint16_t mem_mask)
114 {
115 	uint16_t old = m_pdr;
116 	COMBINE_DATA(&m_pdr);
117 	m_pdr = (old & ~m_pdir) | (m_pdr & m_pdir);
118 	m_out_parallel_cb(0, m_pdr, mem_mask);
119 }
120 
icr_r(offs_t offset)121 uint8_t tmp68301_device::icr_r(offs_t offset)
122 {
123 	return m_icr[offset];
124 }
125 
icr_w(offs_t offset,uint8_t data)126 void tmp68301_device::icr_w(offs_t offset, uint8_t data)
127 {
128 /*
129     --x- ---- Vector number is autogenerated if 1, else use external source
130     ---x x--- 00 falling edge, 01 low level, 10 rising edge, 11 high level
131     ^ applies only to external irqs (offset 0 to 2)
132     ---- -xxx irq level
133 */
134 	m_icr[offset] = data;
135 }
136 
tmp68301_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)137 tmp68301_device::tmp68301_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
138 	: m68000_device(mconfig, TMP68301, tag, owner, clock),
139 		m_in_parallel_cb(*this),
140 		m_out_parallel_cb(*this),
141 		m_ipl(0),
142 		m_imr(0),
143 		m_ipr(0),
144 		m_iisr(0),
145 		m_scr(0),
146 		m_pdir(0),
147 		m_pdr(0)
148 {
149 	memset(m_regs, 0, sizeof(m_regs));
150 	memset(m_icr, 0, sizeof(m_icr));
151 	m_cpu_space_config.m_internal_map = address_map_constructor(FUNC(tmp68301_device::internal_vectors_r), this);
152 }
153 
154 
155 //-------------------------------------------------
156 //  device_start - device-specific startup
157 //-------------------------------------------------
158 
device_start()159 void tmp68301_device::device_start()
160 {
161 	m68000_device::device_start();
162 
163 	for (int i = 0; i < 3; i++)
164 		m_tmp68301_timer[i] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tmp68301_device::timer_callback), this));
165 
166 	m_in_parallel_cb.resolve_safe(0);
167 	m_out_parallel_cb.resolve_safe();
168 
169 	m_program->install_device(0xfffc00, 0xffffff, *this, &tmp68301_device::tmp68301_regs);
170 
171 	save_item(NAME(m_regs));
172 	save_item(NAME(m_icr));
173 	save_item(NAME(m_ipl));
174 	save_item(NAME(m_imr));
175 	save_item(NAME(m_ipr));
176 	save_item(NAME(m_iisr));
177 	save_item(NAME(m_scr));
178 	save_item(NAME(m_pdir));
179 	save_item(NAME(m_pdr));
180 }
181 
182 //-------------------------------------------------
183 //  device_reset - device-specific reset
184 //-------------------------------------------------
185 
device_reset()186 void tmp68301_device::device_reset()
187 {
188 	m68000_device::device_reset();
189 
190 	m_ipr = 0;
191 	m_iisr = 0;
192 	m_imr = 0x7f7; // mask all irqs
193 	std::fill(std::begin(m_icr), std::end(m_icr), 0x07);
194 	update_ipl();
195 }
196 
197 //**************************************************************************
198 //  INLINE HELPERS
199 //**************************************************************************
200 
internal_vectors_r(address_map & map)201 void tmp68301_device::internal_vectors_r(address_map &map)
202 {
203 	map(0xfffff0, 0xffffff).r(FUNC(tmp68301_device::irq_callback)).umask16(0x00ff);
204 }
205 
206 
irq_callback(offs_t offset)207 uint8_t tmp68301_device::irq_callback(offs_t offset)
208 {
209 	uint8_t IVNR = m_regs[0x9a/2] & 0xe0;      // Interrupt Vector Number Register (IVNR)
210 
211 	for (int src : { 0, 7, 3, 1, 8, 4, 5, 9, 2 })
212 	{
213 		// check if the IPL matches
214 		if (offset == (m_icr[src] & 0x07))
215 		{
216 			// check if interrupt is pending and not masked out
217 			u16 mask = (src > 2 ? 2 : 1) << src;
218 			if ((m_ipr & mask) != 0 && (m_imr & mask) == 0)
219 			{
220 				if (!machine().side_effects_disabled())
221 				{
222 					// add cause to interrupt in-service register
223 					m_iisr |= mask;
224 
225 					// no longer pending
226 					m_ipr &= ~mask;
227 					update_ipl();
228 				}
229 
230 				// vary vector number by type
231 				if (src > 6)
232 					return IVNR | (src - 3);
233 				else if (src > 2)
234 					return IVNR | (src - 1) << 2 | serial_interrupt_cause(src - 3);
235 				else /*if (BIT(m_icr[src], 5))*/ // TODO: use external vector otherwise
236 					return IVNR | src;
237 			}
238 		}
239 	}
240 
241 	// default vector
242 	return IVNR | 0x1f;
243 }
244 
TIMER_CALLBACK_MEMBER(tmp68301_device::timer_callback)245 TIMER_CALLBACK_MEMBER(tmp68301_device::timer_callback)
246 {
247 	int i = param;
248 	uint16_t TCR  =   m_regs[(0x200 + i * 0x20)/2];
249 
250 //  logerror("s: callback timer %04X, j = %d\n",machine().describe_context(),i,tcount);
251 
252 	if (TCR & 0x0004)   // INT
253 	{
254 		m_ipr |= 0x100 << i;
255 		update_ipl();
256 	}
257 
258 	if (TCR & 0x0080)   // N/1
259 	{
260 		// Repeat
261 		update_timer(i);
262 	}
263 	else
264 	{
265 		// One Shot
266 	}
267 }
268 
update_timer(int i)269 void tmp68301_device::update_timer(int i)
270 {
271 	uint16_t TCR  =   m_regs[(0x200 + i * 0x20)/2];
272 	uint16_t MAX1 =   m_regs[(0x204 + i * 0x20)/2];
273 	uint16_t MAX2 =   m_regs[(0x206 + i * 0x20)/2];
274 
275 	int max = 0;
276 	attotime duration = attotime::zero;
277 
278 	m_tmp68301_timer[i]->adjust(attotime::never,i);
279 
280 	// timers 1&2 only
281 	switch( (TCR & 0x0030)>>4 )                     // MR2..1
282 	{
283 	case 1:
284 		max = MAX1;
285 		break;
286 	case 2:
287 		max = MAX2;
288 		break;
289 	}
290 
291 	switch ( (TCR & 0xc000)>>14 )                   // CK2..1
292 	{
293 	case 0: // System clock (CLK)
294 		if (max)
295 		{
296 			int scale = (TCR & 0x3c00)>>10;         // P4..1
297 			if (scale > 8) scale = 8;
298 			duration = attotime::from_hz(unscaled_clock()) * ((1 << scale) * max);
299 		}
300 		break;
301 	}
302 
303 //  logerror("%s: TMP68301 Timer %d, duration %lf, max %04X\n",machine().describe_context(),i,duration,max);
304 
305 	if (!(TCR & 0x0002))                // CS
306 	{
307 		if (duration != attotime::zero)
308 			m_tmp68301_timer[i]->adjust(duration,i);
309 		else
310 			logerror("%s: TMP68301 error, timer %d duration is 0\n",machine().describe_context(),i);
311 	}
312 }
313 
314 /* Update the IRQ state based on all possible causes */
update_ipl()315 void tmp68301_device::update_ipl()
316 {
317 	uint8_t new_ipl = 0;
318 
319 	for (int src = 0; src < 10; src++)
320 	{
321 		u16 mask = (src > 2 ? 2 : 1) << src;
322 		if ((m_ipr & mask) != 0 && (m_imr & mask) == 0 && new_ipl < (m_icr[src] & 0x07))
323 			new_ipl = m_icr[src] & 0x07;
324 	}
325 
326 	if (new_ipl != m_ipl)
327 	{
328 		if (m_ipl != 0)
329 			set_input_line(m_ipl, CLEAR_LINE);
330 		if (new_ipl != 0)
331 			set_input_line(new_ipl, ASSERT_LINE);
332 
333 		m_ipl = new_ipl;
334 	}
335 }
336 
serial_interrupt_cause(int channel)337 uint8_t tmp68301_device::serial_interrupt_cause(int channel)
338 {
339 	/*
340 	 *  00 error occurred
341 	 *  01 receive completed
342 	 *  10 transmit ready
343 	 *  11 interrupt cause cleared while interrupt pending
344 	 */
345 	(void)channel;
346 	return 3;
347 }
348 
349 
regs_r(offs_t offset)350 uint16_t tmp68301_device::regs_r(offs_t offset)
351 {
352 	return m_regs[offset];
353 }
354 
regs_w(offs_t offset,uint16_t data,uint16_t mem_mask)355 void tmp68301_device::regs_w(offs_t offset, uint16_t data, uint16_t mem_mask)
356 {
357 	COMBINE_DATA(&m_regs[offset]);
358 
359 	if (!ACCESSING_BITS_0_7)    return;
360 
361 //  logerror("CPU #0 PC %06X: TMP68301 Reg %04X<-%04X & %04X\n", >pc(),offset*2,data,mem_mask^0xffff);
362 
363 	switch( offset * 2 )
364 	{
365 		// Timers
366 		case 0x200:
367 		case 0x220:
368 		case 0x240:
369 		{
370 			int i = ((offset*2) >> 5) & 3;
371 
372 			update_timer( i );
373 		}
374 		break;
375 	}
376 }
377 
external_interrupt_0()378 void tmp68301_device::external_interrupt_0()    { m_ipr |= EXT_IRQ0; update_ipl(); }
external_interrupt_1()379 void tmp68301_device::external_interrupt_1()    { m_ipr |= EXT_IRQ1; update_ipl(); }
external_interrupt_2()380 void tmp68301_device::external_interrupt_2()    { m_ipr |= EXT_IRQ2; update_ipl(); }
381