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