1 // license:BSD-3-Clause
2 // copyright-holders:hap, Tim Lindner
3 /*****************************************************************************
4
5 Texas Instruments TMS7000
6
7 TODO:
8 - dump CROM and emulate cpu at microinstruction level
9 - memory modes with IOCNT0, currently always running in faked full expansion mode
10 - timer event counter mode (timer control register, bit 6)
11 - TMS70x1/2 serial port and timer 3
12 - TMS70C46 DOCK-BUS comms with external pins
13 - TMS70C46 external memory mode is via "E" bus instead of configuring IOCNT0
14 - TMS70C46 clock divider
15 - TMS70C46 INT3 on keypress
16 - when they're needed, add TMS70Cx2, TMS7742, TMS77C82, SE70xxx
17
18 *****************************************************************************/
19
20 #include "emu.h"
21 #include "tms7000.h"
22 #include "7000dasm.h"
23
24 // TMS7000 is the most basic one, 128 bytes internal RAM and no internal ROM.
25 // TMS7020 and TMS7040 are same, but with 2KB and 4KB internal ROM respectively.
26 DEFINE_DEVICE_TYPE(TMS7000, tms7000_device, "tms7000", "Texas Instruments TMS7000")
27 DEFINE_DEVICE_TYPE(TMS7020, tms7020_device, "tms7020", "Texas Instruments TMS7020")
28 DEFINE_DEVICE_TYPE(TMS7040, tms7040_device, "tms7040", "Texas Instruments TMS7040")
29
30 // Exelvision (spinoff of TI) TMS7020 added one custom opcode.
31 DEFINE_DEVICE_TYPE(TMS7020_EXL, tms7020_exl_device, "tms7020_exl", "Texas Instruments TMS7020 (Exelvision)")
32
33 // CMOS devices biggest difference in a 'real world' setting is that the power
34 // requirements are much lower. This obviously has no use in software emulation.
35 DEFINE_DEVICE_TYPE(TMS70C00, tms70c00_device, "tms70c00", "Texas Instruments TMS70C00")
36 DEFINE_DEVICE_TYPE(TMS70C20, tms70c20_device, "tms70c20", "Texas Instruments TMS70C20")
37 DEFINE_DEVICE_TYPE(TMS70C40, tms70c40_device, "tms70c40", "Texas Instruments TMS70C40")
38
39 // TMS70x1 features more peripheral I/O, the main addition being a serial port.
40 // TMS70x2 is the same, just with twice more RAM (256 bytes)
41 DEFINE_DEVICE_TYPE(TMS7001, tms7001_device, "tms7001", "Texas Instruments TMS7001")
42 DEFINE_DEVICE_TYPE(TMS7041, tms7041_device, "tms7041", "Texas Instruments TMS7041")
43 DEFINE_DEVICE_TYPE(TMS7002, tms7002_device, "tms7002", "Texas Instruments TMS7002")
44 DEFINE_DEVICE_TYPE(TMS7042, tms7042_device, "tms7042", "Texas Instruments TMS7042")
45
46 // TMS70C46 is literally a shell around a TMS70C40, with support for external
47 // memory bus, auto external clock divider on slow memory, and wake-up on keypress.
48 DEFINE_DEVICE_TYPE(TMS70C46, tms70c46_device, "tms70c46", "Texas Instruments TMS70C46")
49
50 // TMS70Cx2 is an update to TMS70x2 with some extra features. Due to some changes
51 // in peripheral file I/O, it is not backward compatible to TMS70x2.
52
53
54 // internal memory maps
tms7000_mem(address_map & map)55 void tms7000_device::tms7000_mem(address_map &map)
56 {
57 map(0x0000, 0x007f).ram().share("rf"); // 128 bytes internal RAM
58 map(0x0080, 0x00ff).rw(FUNC(tms7000_device::tms7000_unmapped_rf_r), FUNC(tms7000_device::tms7000_unmapped_rf_w));
59 map(0x0100, 0x010b).rw(FUNC(tms7000_device::tms7000_pf_r), FUNC(tms7000_device::tms7000_pf_w));
60 map(0x0104, 0x0105).nopw(); // no port A write or ddr
61 }
62
tms7001_mem(address_map & map)63 void tms7000_device::tms7001_mem(address_map &map)
64 {
65 map(0x0000, 0x007f).ram().share("rf"); // 128 bytes internal RAM
66 map(0x0080, 0x00ff).rw(FUNC(tms7000_device::tms7000_unmapped_rf_r), FUNC(tms7000_device::tms7000_unmapped_rf_w));
67 map(0x0100, 0x010b).rw(FUNC(tms7000_device::tms7000_pf_r), FUNC(tms7000_device::tms7000_pf_w));
68 map(0x0110, 0x0117).rw(FUNC(tms7000_device::tms7002_pf_r), FUNC(tms7000_device::tms7002_pf_w));
69 }
70
tms7002_mem(address_map & map)71 void tms7000_device::tms7002_mem(address_map &map)
72 {
73 map(0x0000, 0x00ff).ram().share("rf"); // 256 bytes internal RAM
74 map(0x0100, 0x010b).rw(FUNC(tms7000_device::tms7000_pf_r), FUNC(tms7000_device::tms7000_pf_w));
75 map(0x0110, 0x0117).rw(FUNC(tms7000_device::tms7002_pf_r), FUNC(tms7000_device::tms7002_pf_w));
76 }
77
tms7020_mem(address_map & map)78 void tms7000_device::tms7020_mem(address_map &map)
79 {
80 tms7000_mem(map);
81 map(0xf800, 0xffff).rom().region(DEVICE_SELF, 0); // 2kB internal ROM
82 }
83
tms7040_mem(address_map & map)84 void tms7000_device::tms7040_mem(address_map &map)
85 {
86 tms7000_mem(map);
87 map(0xf000, 0xffff).rom().region(DEVICE_SELF, 0); // 4kB internal ROM
88 }
89
tms7041_mem(address_map & map)90 void tms7000_device::tms7041_mem(address_map &map)
91 {
92 tms7001_mem(map);
93 map(0xf000, 0xffff).rom().region(DEVICE_SELF, 0);
94 }
95
tms7042_mem(address_map & map)96 void tms7000_device::tms7042_mem(address_map &map)
97 {
98 tms7002_mem(map);
99 map(0xf000, 0xffff).rom().region(DEVICE_SELF, 0);
100 }
101
tms70c46_mem(address_map & map)102 void tms70c46_device::tms70c46_mem(address_map &map)
103 {
104 tms7040_mem(map);
105 map(0x010c, 0x010c).rw(FUNC(tms70c46_device::e_bus_data_r), FUNC(tms70c46_device::e_bus_data_w));
106 map(0x010d, 0x010d).noprw(); // ? always writes $FF before checking keyboard... maybe INT3 ack?
107 map(0x010e, 0x010e).rw(FUNC(tms70c46_device::dockbus_data_r), FUNC(tms70c46_device::dockbus_data_w));
108 map(0x010f, 0x010f).rw(FUNC(tms70c46_device::dockbus_status_r), FUNC(tms70c46_device::dockbus_status_w));
109 map(0x0118, 0x0118).rw(FUNC(tms70c46_device::control_r), FUNC(tms70c46_device::control_w));
110 }
111
112
113 // device definitions
tms7000_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)114 tms7000_device::tms7000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
115 tms7000_device(mconfig, TMS7000, tag, owner, clock, address_map_constructor(FUNC(tms7000_device::tms7000_mem), this), 0)
116 {
117 }
118
tms7000_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock,address_map_constructor internal,uint32_t info_flags)119 tms7000_device::tms7000_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal, uint32_t info_flags) :
120 cpu_device(mconfig, type, tag, owner, clock),
121 m_program_config("program", ENDIANNESS_BIG, 8, 16, 0, internal),
122 m_port_in_cb(*this),
123 m_port_out_cb(*this),
124 m_info_flags(info_flags),
125 m_divider(2)
126 {
127 }
128
tms7020_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)129 tms7020_device::tms7020_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
130 tms7000_device(mconfig, TMS7020, tag, owner, clock, address_map_constructor(FUNC(tms7020_device::tms7020_mem), this), 0)
131 {
132 }
133
tms7020_exl_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)134 tms7020_exl_device::tms7020_exl_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
135 tms7000_device(mconfig, TMS7020_EXL, tag, owner, clock, address_map_constructor(FUNC(tms7020_exl_device::tms7020_mem), this), 0)
136 {
137 }
138
tms7040_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)139 tms7040_device::tms7040_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
140 tms7000_device(mconfig, TMS7040, tag, owner, clock, address_map_constructor(FUNC(tms7040_device::tms7040_mem), this), 0)
141 {
142 }
143
tms70c00_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)144 tms70c00_device::tms70c00_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
145 tms7000_device(mconfig, TMS70C00, tag, owner, clock, address_map_constructor(FUNC(tms70c00_device::tms7000_mem), this), CHIP_IS_CMOS)
146 {
147 }
148
tms70c20_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)149 tms70c20_device::tms70c20_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
150 tms7000_device(mconfig, TMS70C20, tag, owner, clock, address_map_constructor(FUNC(tms70c20_device::tms7020_mem), this), CHIP_IS_CMOS)
151 {
152 }
153
tms70c40_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)154 tms70c40_device::tms70c40_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
155 tms7000_device(mconfig, TMS70C40, tag, owner, clock, address_map_constructor(FUNC(tms70c40_device::tms7040_mem), this), CHIP_IS_CMOS)
156 {
157 }
158
tms7001_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)159 tms7001_device::tms7001_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
160 tms7000_device(mconfig, TMS7001, tag, owner, clock, address_map_constructor(FUNC(tms7001_device::tms7001_mem), this), CHIP_FAMILY_70X2)
161 {
162 }
163
tms7041_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)164 tms7041_device::tms7041_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
165 tms7000_device(mconfig, TMS7041, tag, owner, clock, address_map_constructor(FUNC(tms7041_device::tms7041_mem), this), CHIP_FAMILY_70X2)
166 {
167 }
168
tms7002_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)169 tms7002_device::tms7002_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
170 tms7000_device(mconfig, TMS7002, tag, owner, clock, address_map_constructor(FUNC(tms7002_device::tms7002_mem), this), CHIP_FAMILY_70X2)
171 {
172 }
173
tms7042_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)174 tms7042_device::tms7042_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
175 tms7000_device(mconfig, TMS7042, tag, owner, clock, address_map_constructor(FUNC(tms7042_device::tms7042_mem), this), CHIP_FAMILY_70X2)
176 {
177 }
178
tms70c46_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)179 tms70c46_device::tms70c46_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
180 tms7000_device(mconfig, TMS70C46, tag, owner, clock, address_map_constructor(FUNC(tms70c46_device::tms70c46_mem), this), CHIP_IS_CMOS)
181 {
182 }
183
memory_space_config() const184 device_memory_interface::space_config_vector tms7000_device::memory_space_config() const
185 {
186 return space_config_vector {
187 std::make_pair(AS_PROGRAM, &m_program_config)
188 };
189 }
190
191
192 //-------------------------------------------------
193 // device_start - device-specific startup
194 //-------------------------------------------------
195
device_start()196 void tms7000_device::device_start()
197 {
198 // init/zerofill
199 space(AS_PROGRAM).cache(m_cache);
200 space(AS_PROGRAM).specific(m_program);
201
202 set_icountptr(m_icount);
203
204 m_irq_state[TMS7000_INT1_LINE] = false;
205 m_irq_state[TMS7000_INT3_LINE] = false;
206
207 m_port_in_cb.resolve_all_safe(0xff);
208 m_port_out_cb.resolve_all_safe();
209
210 m_idle_state = false;
211 m_idle_halt = false;
212 m_pc = 0;
213 m_sp = 0;
214 m_sr = 0;
215 m_op = 0;
216
217 memset(m_io_control, 0, 3);
218
219 memset(m_port_latch, 0, 4);
220 memset(m_port_ddr, 0, 4);
221 m_port_ddr[1] = 0xff; // !
222
223 for (int tmr = 0; tmr < 2; tmr++)
224 {
225 m_timer_handle[tmr] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(tms7000_device::simple_timer_cb), this));
226 m_timer_handle[tmr]->adjust(attotime::never, tmr);
227
228 m_timer_data[tmr] = 0;
229 m_timer_control[tmr] = 0;
230 m_timer_decrementer[tmr] = 0;
231 m_timer_prescaler[tmr] = 0;
232 m_timer_capture_latch[tmr] = 0;
233 }
234
235 // register for savestates
236 save_item(NAME(m_irq_state));
237 save_item(NAME(m_idle_state));
238 save_item(NAME(m_pc));
239 save_item(NAME(m_sp));
240 save_item(NAME(m_sr));
241 save_item(NAME(m_op));
242
243 save_item(NAME(m_io_control));
244 save_item(NAME(m_port_latch));
245 save_item(NAME(m_port_ddr));
246 save_item(NAME(m_timer_data));
247 save_item(NAME(m_timer_control));
248 save_item(NAME(m_timer_decrementer));
249 save_item(NAME(m_timer_prescaler));
250 save_item(NAME(m_timer_capture_latch));
251
252 // register for debugger
253 state_add(TMS7000_PC, "PC", m_pc).formatstr("%04X");
254 state_add(TMS7000_SP, "SP", m_sp).formatstr("%02X");
255 state_add(TMS7000_ST, "ST", m_sr).formatstr("%02X");
256
257 uint8_t *rf = static_cast<uint8_t *>(memshare("rf")->ptr());
258 state_add(TMS7000_A, "A", rf[0]).formatstr("%02X");
259 state_add(TMS7000_B, "B", rf[1]).formatstr("%02X");
260
261 state_add(STATE_GENPC, "GENPC", m_pc).formatstr("%04X").noshow();
262 state_add(STATE_GENPCBASE, "CURPC", m_pc).formatstr("%04X").noshow();
263 state_add(STATE_GENSP, "GENSP", m_sp).formatstr("%02X").noshow();
264 state_add(STATE_GENFLAGS, "GENFLAGS", m_sr).formatstr("%8s").noshow();
265 }
266
state_string_export(const device_state_entry & entry,std::string & str) const267 void tms7000_device::state_string_export(const device_state_entry &entry, std::string &str) const
268 {
269 switch (entry.index())
270 {
271 case STATE_GENFLAGS:
272 str = string_format("%c%c%c%c%c%c%c%c",
273 m_sr & 0x80 ? 'C':'c',
274 m_sr & 0x40 ? 'N':'n',
275 m_sr & 0x20 ? 'Z':'z',
276 m_sr & 0x10 ? 'I':'i',
277 m_sr & 0x08 ? '?':'.',
278 m_sr & 0x04 ? '?':'.',
279 m_sr & 0x02 ? '?':'.',
280 m_sr & 0x01 ? '?':'.'
281 );
282 break;
283
284 default: break;
285 }
286 }
287
create_disassembler()288 std::unique_ptr<util::disasm_interface> tms7000_device::create_disassembler()
289 {
290 return std::make_unique<tms7000_disassembler>();
291 }
292
293
294 //-------------------------------------------------
295 // device_reset - device-specific reset
296 //-------------------------------------------------
297
device_reset()298 void tms7000_device::device_reset()
299 {
300 if (m_idle_state)
301 {
302 m_pc++;
303 m_idle_state = false;
304 }
305
306 // while _RESET is asserted:
307 // clear ports
308 write_p(0x04, 0xff); // port a
309 write_p(0x06, 0xff); // port b
310
311 write_p(0x05, 0x00); // ddr a
312 write_p(0x09, 0x00); // ddr c
313 write_p(0x0b, 0x00); // ddr d
314
315 if (!chip_is_cmos())
316 {
317 write_p(0x08, 0xff); // port c
318 write_p(0x0a, 0xff); // port d
319 }
320
321 // when _RESET goes inactive (0 to 1)
322 m_sr = 0;
323
324 write_p(0x00, 0x00); // IOCNT0
325 if (chip_is_family_70x2())
326 write_p(0x10, 0x00); // IOCNT1
327
328 m_sp = 0xff;
329 m_op = 0xff;
330 execute_one(m_op);
331 m_icount -= 3; // 17 total
332 }
333
334
335 //-------------------------------------------------
336 // interrupts
337 //-------------------------------------------------
338
execute_set_input(int extline,int state)339 void tms7000_device::execute_set_input(int extline, int state)
340 {
341 if (extline != TMS7000_INT1_LINE && extline != TMS7000_INT3_LINE)
342 return;
343
344 bool irqstate = (state == CLEAR_LINE) ? false : true;
345
346 // reverse polarity (TMS70cx2-only)
347 if (m_io_control[2] & (0x01 << (4 * extline)))
348 irqstate = !irqstate;
349
350 if (m_irq_state[extline] != irqstate)
351 {
352 m_irq_state[extline] = irqstate;
353
354 // set/clear internal irq flag
355 flag_ext_interrupt(extline);
356
357 if (m_irq_state[extline])
358 {
359 // latch timer 1 on INT3
360 if (extline == TMS7000_INT3_LINE)
361 m_timer_capture_latch[0] = m_timer_decrementer[0];
362
363 // on TMS70cx2, latch timer 2 on INT1
364 if (extline == TMS7000_INT1_LINE && chip_is_family_70cx2())
365 m_timer_capture_latch[1] = m_timer_decrementer[1];
366
367 // clear external if it's edge-triggered (TMS70cx2-only)
368 if (m_io_control[2] & (0x02 << (4 * extline)))
369 m_irq_state[extline] = false;
370
371 check_interrupts();
372 }
373 }
374 }
375
flag_ext_interrupt(int extline)376 void tms7000_device::flag_ext_interrupt(int extline)
377 {
378 if (extline != TMS7000_INT1_LINE && extline != TMS7000_INT3_LINE)
379 return;
380
381 // set/clear for pending external interrupt
382 if (m_irq_state[extline])
383 m_io_control[0] |= (0x02 << (4 * extline));
384 else
385 m_io_control[0] &= ~(0x02 << (4 * extline));
386 }
387
check_interrupts()388 void tms7000_device::check_interrupts()
389 {
390 // global interrupt bit
391 if (!(m_sr & SR_I))
392 return;
393
394 // check for and handle interrupt
395 for (int irqline = 0; irqline < 5; irqline++)
396 {
397 // INT 1,2,3 are in IOCNT0 d0-d5
398 // INT 4,5 are in IOCNT1 d0-d3
399 int shift = (irqline > 2) ? irqline * 2 - 6 : irqline * 2;
400 if ((m_io_control[irqline > 2] >> shift & 3) == 3)
401 {
402 // ack
403 m_io_control[irqline > 2] &= ~(0x02 << shift);
404 if (irqline == 0 || irqline == 2)
405 flag_ext_interrupt(irqline / 2);
406
407 do_interrupt(irqline);
408 return;
409 }
410 }
411 }
412
do_interrupt(int irqline)413 void tms7000_device::do_interrupt(int irqline)
414 {
415 if (m_idle_state)
416 {
417 m_icount -= 17;
418 m_pc++;
419 m_idle_state = false;
420 }
421 else
422 m_icount -= 19;
423
424 push8(m_sr);
425 push16(m_pc);
426 m_sr = 0;
427 m_pc = read_mem16(0xfffc - irqline * 2);
428
429 standard_irq_callback(irqline);
430 }
431
432
433 //-------------------------------------------------
434 // timers
435 //-------------------------------------------------
436
timer_run(int tmr)437 void tms7000_device::timer_run(int tmr)
438 {
439 m_timer_prescaler[tmr] = m_timer_control[tmr] & 0x1f;
440
441 // run automatic timer if source is internal
442 if ((m_timer_control[tmr] & 0xe0) == 0x80)
443 {
444 attotime period = attotime::from_hz(clock()) * 16 * (m_timer_prescaler[tmr] + 1); // fOSC/16 - fOSC is freq _before_ internal clockdivider
445 m_timer_handle[tmr]->adjust(period, tmr);
446 }
447 }
448
timer_reload(int tmr)449 void tms7000_device::timer_reload(int tmr)
450 {
451 // stop possible running timer
452 m_timer_handle[tmr]->adjust(attotime::never, tmr);
453
454 if (m_timer_control[tmr] & 0x80)
455 {
456 m_timer_decrementer[tmr] = m_timer_data[tmr];
457 timer_run(tmr);
458 }
459 }
460
timer_tick_pre(int tmr)461 void tms7000_device::timer_tick_pre(int tmr)
462 {
463 // timer prescaler underflow
464 if (--m_timer_prescaler[tmr] < 0)
465 {
466 m_timer_prescaler[tmr] = m_timer_control[tmr] & 0x1f;
467 timer_tick_low(tmr);
468 }
469 }
470
timer_tick_low(int tmr)471 void tms7000_device::timer_tick_low(int tmr)
472 {
473 // timer decrementer underflow
474 if (--m_timer_decrementer[tmr] < 0)
475 {
476 timer_reload(tmr);
477
478 // set INT2/INT5
479 m_io_control[tmr] |= 0x08;
480
481 // cascaded timer
482 if (tmr == 0 && (m_timer_control[1] & 0xa0) == 0xa0)
483 timer_tick_pre(tmr + 1);
484 }
485 }
486
TIMER_CALLBACK_MEMBER(tms7000_device::simple_timer_cb)487 TIMER_CALLBACK_MEMBER(tms7000_device::simple_timer_cb)
488 {
489 int tmr = param;
490
491 // tick and restart timer
492 timer_tick_low(tmr);
493 timer_run(tmr);
494 }
495
496
497 //-------------------------------------------------
498 // peripheral file - read/write internal ports
499 // note: TMS7000 family is from $00 to $0b, TMS7002 family adds $10 to $17
500 //-------------------------------------------------
501
tms7000_pf_r(offs_t offset)502 uint8_t tms7000_device::tms7000_pf_r(offs_t offset)
503 {
504 switch (offset)
505 {
506 // i/o control
507 case 0x00: case 0x10:
508 return m_io_control[offset >> 4];
509
510 // timer 1/2 data
511 case 0x02: case 0x12:
512 // current decrementer value
513 return m_timer_decrementer[offset >> 4];
514
515 // timer 1 control
516 case 0x03:
517 // timer capture (latched by INT3)
518 return m_timer_capture_latch[0];
519
520 // port data
521 case 0x04: case 0x06: case 0x08: case 0x0a:
522 {
523 // note: port B is write-only, reading it returns the output value as if ddr is 0xff
524 int port = offset / 2 - 2;
525 if (!machine().side_effects_disabled())
526 return (m_port_in_cb[port]() & ~m_port_ddr[port]) | (m_port_latch[port] & m_port_ddr[port]);
527 break;
528 }
529
530 // port direction (note: TMS7000 doesn't support it for port A)
531 case 0x05: case 0x09: case 0x0b:
532 return m_port_ddr[offset / 2 - 2];
533
534 default:
535 if (!machine().side_effects_disabled())
536 logerror("'%s' (%04X): tms7000_pf_r @ $%04x\n", tag(), m_pc, offset);
537 break;
538 }
539
540 return 0;
541 }
542
tms7000_pf_w(offs_t offset,uint8_t data)543 void tms7000_device::tms7000_pf_w(offs_t offset, uint8_t data)
544 {
545 switch (offset)
546 {
547 // i/o control (IOCNT0)
548 case 0x00:
549 // d0,d2,d4: INT1,2,3 enable
550 // d1,d3,d5: INT1,2,3 flag (write 1 to clear flag)
551 // d6-d7: memory mode (currently not implemented)
552 m_io_control[0] = (m_io_control[0] & (~data & 0x2a)) | (data & 0xd5);
553
554 // possibly need to reactivate flags
555 if (data & 0x02)
556 flag_ext_interrupt(TMS7000_INT1_LINE);
557 if (data & 0x20)
558 flag_ext_interrupt(TMS7000_INT3_LINE);
559
560 check_interrupts();
561 break;
562
563 // i/o control (IOCNT1)
564 case 0x10:
565 // d0,d2: INT4,5 enable
566 // d1,d3: INT4,5 flag (write 1 to clear flag)
567 m_io_control[1] = (m_io_control[1] & (~data & 0x0a)) | (data & 0x05);
568 check_interrupts();
569 break;
570
571 // timer 1/2 data
572 case 0x02: case 0x12:
573 // decrementer reload value
574 m_timer_data[offset >> 4] = data;
575 break;
576
577 // timer 1/2 control
578 case 0x03:
579 // d5: t1: cmos low-power mode when IDLE opcode is used (not emulated)
580 // 0(normal), or 1(halt) - indicating it can only wake up with RESET or external interrupt
581 if (chip_is_cmos())
582 {
583 m_idle_halt = (data & 0x20) ? true : false;
584 if (m_idle_halt)
585 logerror("%s: CMOS low-power halt mode enabled\n", tag());
586 }
587 data &= ~0x20;
588 case 0x13:
589 // d0-d4: prescaler reload value
590 // d5: t2: cascade from t1
591 // d6: source (internal/external)
592 // d7: stop/start timer
593 m_timer_control[offset >> 4] = data;
594 timer_reload(offset >> 4);
595
596 // on cmos chip, clear INT2/INT5 as well
597 if (~data & 0x80 && chip_is_cmos())
598 m_io_control[offset >> 4] &= ~0x08;
599
600 break;
601
602 // port data (note: TMS7000 doesn't support it for port A)
603 case 0x04: case 0x06: case 0x08: case 0x0a:
604 {
605 // note: in memory expansion modes, some port output pins are used for memory strobes.
606 // this is currently ignored, since port writes will always be visible externally on peripheral expansion anyway.
607 int port = offset / 2 - 2;
608 m_port_out_cb[port](data & m_port_ddr[port]);
609 m_port_latch[port] = data;
610 break;
611 }
612
613 // port direction (note: TMS7000 doesn't support it for port A)
614 case 0x05: case 0x09: case 0x0b:
615 // note: changing port direction does not change(refresh) the output pins
616 m_port_ddr[offset / 2 - 2] = data;
617 break;
618
619 default:
620 logerror("'%s' (%04X): tms7000_pf_w @ $%04x = $%02x\n", tag(), m_pc, offset, data);
621 break;
622 }
623 }
624
625
626 //-------------------------------------------------
627 // execute
628 //-------------------------------------------------
629
execute_run()630 void tms7000_device::execute_run()
631 {
632 check_interrupts();
633
634 do
635 {
636 debugger_instruction_hook(m_pc);
637
638 m_op = m_cache.read_byte(m_pc++);
639 execute_one(m_op);
640 } while (m_icount > 0);
641 }
642
execute_one(uint8_t op)643 void tms7000_device::execute_one(uint8_t op)
644 {
645 switch (op)
646 {
647 case 0x00: nop(); break;
648 case 0x01: idle(); break;
649 case 0x05: eint(); break;
650 case 0x06: dint(); break;
651 case 0x07: setc(); break;
652 case 0x08: pop_st(); break;
653 case 0x09: stsp(); break;
654 case 0x0a: rets(); break;
655 case 0x0b: reti(); break;
656 case 0x0d: ldsp(); break;
657 case 0x0e: push_st(); break;
658
659 case 0x12: am_r2a(&tms7000_device::op_mov); break;
660 case 0x13: am_r2a(&tms7000_device::op_and); break;
661 case 0x14: am_r2a(&tms7000_device::op_or); break;
662 case 0x15: am_r2a(&tms7000_device::op_xor); break;
663 case 0x16: am_r2a(&tms7000_device::op_btjo); break;
664 case 0x17: am_r2a(&tms7000_device::op_btjz); break;
665 case 0x18: am_r2a(&tms7000_device::op_add); break;
666 case 0x19: am_r2a(&tms7000_device::op_adc); break;
667 case 0x1a: am_r2a(&tms7000_device::op_sub); break;
668 case 0x1b: am_r2a(&tms7000_device::op_sbb); break;
669 case 0x1c: am_r2a(&tms7000_device::op_mpy); break;
670 case 0x1d: am_r2a(&tms7000_device::op_cmp); break;
671 case 0x1e: am_r2a(&tms7000_device::op_dac); break;
672 case 0x1f: am_r2a(&tms7000_device::op_dsb); break;
673
674 case 0x22: am_i2a(&tms7000_device::op_mov); break;
675 case 0x23: am_i2a(&tms7000_device::op_and); break;
676 case 0x24: am_i2a(&tms7000_device::op_or); break;
677 case 0x25: am_i2a(&tms7000_device::op_xor); break;
678 case 0x26: am_i2a(&tms7000_device::op_btjo); break;
679 case 0x27: am_i2a(&tms7000_device::op_btjz); break;
680 case 0x28: am_i2a(&tms7000_device::op_add); break;
681 case 0x29: am_i2a(&tms7000_device::op_adc); break;
682 case 0x2a: am_i2a(&tms7000_device::op_sub); break;
683 case 0x2b: am_i2a(&tms7000_device::op_sbb); break;
684 case 0x2c: am_i2a(&tms7000_device::op_mpy); break;
685 case 0x2d: am_i2a(&tms7000_device::op_cmp); break;
686 case 0x2e: am_i2a(&tms7000_device::op_dac); break;
687 case 0x2f: am_i2a(&tms7000_device::op_dsb); break;
688
689 case 0x32: am_r2b(&tms7000_device::op_mov); break;
690 case 0x33: am_r2b(&tms7000_device::op_and); break;
691 case 0x34: am_r2b(&tms7000_device::op_or); break;
692 case 0x35: am_r2b(&tms7000_device::op_xor); break;
693 case 0x36: am_r2b(&tms7000_device::op_btjo); break;
694 case 0x37: am_r2b(&tms7000_device::op_btjz); break;
695 case 0x38: am_r2b(&tms7000_device::op_add); break;
696 case 0x39: am_r2b(&tms7000_device::op_adc); break;
697 case 0x3a: am_r2b(&tms7000_device::op_sub); break;
698 case 0x3b: am_r2b(&tms7000_device::op_sbb); break;
699 case 0x3c: am_r2b(&tms7000_device::op_mpy); break;
700 case 0x3d: am_r2b(&tms7000_device::op_cmp); break;
701 case 0x3e: am_r2b(&tms7000_device::op_dac); break;
702 case 0x3f: am_r2b(&tms7000_device::op_dsb); break;
703
704 case 0x42: am_r2r(&tms7000_device::op_mov); break;
705 case 0x43: am_r2r(&tms7000_device::op_and); break;
706 case 0x44: am_r2r(&tms7000_device::op_or); break;
707 case 0x45: am_r2r(&tms7000_device::op_xor); break;
708 case 0x46: am_r2r(&tms7000_device::op_btjo); break;
709 case 0x47: am_r2r(&tms7000_device::op_btjz); break;
710 case 0x48: am_r2r(&tms7000_device::op_add); break;
711 case 0x49: am_r2r(&tms7000_device::op_adc); break;
712 case 0x4a: am_r2r(&tms7000_device::op_sub); break;
713 case 0x4b: am_r2r(&tms7000_device::op_sbb); break;
714 case 0x4c: am_r2r(&tms7000_device::op_mpy); break;
715 case 0x4d: am_r2r(&tms7000_device::op_cmp); break;
716 case 0x4e: am_r2r(&tms7000_device::op_dac); break;
717 case 0x4f: am_r2r(&tms7000_device::op_dsb); break;
718
719 case 0x52: am_i2b(&tms7000_device::op_mov); break;
720 case 0x53: am_i2b(&tms7000_device::op_and); break;
721 case 0x54: am_i2b(&tms7000_device::op_or); break;
722 case 0x55: am_i2b(&tms7000_device::op_xor); break;
723 case 0x56: am_i2b(&tms7000_device::op_btjo); break;
724 case 0x57: am_i2b(&tms7000_device::op_btjz); break;
725 case 0x58: am_i2b(&tms7000_device::op_add); break;
726 case 0x59: am_i2b(&tms7000_device::op_adc); break;
727 case 0x5a: am_i2b(&tms7000_device::op_sub); break;
728 case 0x5b: am_i2b(&tms7000_device::op_sbb); break;
729 case 0x5c: am_i2b(&tms7000_device::op_mpy); break;
730 case 0x5d: am_i2b(&tms7000_device::op_cmp); break;
731 case 0x5e: am_i2b(&tms7000_device::op_dac); break;
732 case 0x5f: am_i2b(&tms7000_device::op_dsb); break;
733
734 case 0x62: am_b2a(&tms7000_device::op_mov); break;
735 case 0x63: am_b2a(&tms7000_device::op_and); break;
736 case 0x64: am_b2a(&tms7000_device::op_or); break;
737 case 0x65: am_b2a(&tms7000_device::op_xor); break;
738 case 0x66: am_b2a(&tms7000_device::op_btjo); break;
739 case 0x67: am_b2a(&tms7000_device::op_btjz); break;
740 case 0x68: am_b2a(&tms7000_device::op_add); break;
741 case 0x69: am_b2a(&tms7000_device::op_adc); break;
742 case 0x6a: am_b2a(&tms7000_device::op_sub); break;
743 case 0x6b: am_b2a(&tms7000_device::op_sbb); break;
744 case 0x6c: am_b2a(&tms7000_device::op_mpy); break;
745 case 0x6d: am_b2a(&tms7000_device::op_cmp); break;
746 case 0x6e: am_b2a(&tms7000_device::op_dac); break;
747 case 0x6f: am_b2a(&tms7000_device::op_dsb); break;
748
749 case 0x72: am_i2r(&tms7000_device::op_mov); break;
750 case 0x73: am_i2r(&tms7000_device::op_and); break;
751 case 0x74: am_i2r(&tms7000_device::op_or); break;
752 case 0x75: am_i2r(&tms7000_device::op_xor); break;
753 case 0x76: am_i2r(&tms7000_device::op_btjo); break;
754 case 0x77: am_i2r(&tms7000_device::op_btjz); break;
755 case 0x78: am_i2r(&tms7000_device::op_add); break;
756 case 0x79: am_i2r(&tms7000_device::op_adc); break;
757 case 0x7a: am_i2r(&tms7000_device::op_sub); break;
758 case 0x7b: am_i2r(&tms7000_device::op_sbb); break;
759 case 0x7c: am_i2r(&tms7000_device::op_mpy); break;
760 case 0x7d: am_i2r(&tms7000_device::op_cmp); break;
761 case 0x7e: am_i2r(&tms7000_device::op_dac); break;
762 case 0x7f: am_i2r(&tms7000_device::op_dsb); break;
763
764 case 0x80: am_p2a(&tms7000_device::op_mov); break;
765 case 0x82: am_a2p(&tms7000_device::op_mov); break;
766 case 0x83: am_a2p(&tms7000_device::op_and); break;
767 case 0x84: am_a2p(&tms7000_device::op_or); break;
768 case 0x85: am_a2p(&tms7000_device::op_xor); break;
769 case 0x86: am_a2p(&tms7000_device::op_btjo); break;
770 case 0x87: am_a2p(&tms7000_device::op_btjz); break;
771 case 0x88: movd_dir(); break;
772 case 0x8a: lda_dir(); break;
773 case 0x8b: sta_dir(); break;
774 case 0x8c: br_dir(); break;
775 case 0x8d: cmpa_dir(); break;
776 case 0x8e: call_dir(); break;
777
778 case 0x91: am_p2b(&tms7000_device::op_mov); break;
779 case 0x92: am_b2p(&tms7000_device::op_mov); break;
780 case 0x93: am_b2p(&tms7000_device::op_and); break;
781 case 0x94: am_b2p(&tms7000_device::op_or); break;
782 case 0x95: am_b2p(&tms7000_device::op_xor); break;
783 case 0x96: am_b2p(&tms7000_device::op_btjo); break;
784 case 0x97: am_b2p(&tms7000_device::op_btjz); break;
785 case 0x98: movd_ind(); break;
786 case 0x9a: lda_ind(); break;
787 case 0x9b: sta_ind(); break;
788 case 0x9c: br_ind(); break;
789 case 0x9d: cmpa_ind(); break;
790 case 0x9e: call_ind(); break;
791
792 case 0xa2: am_i2p(&tms7000_device::op_mov); break;
793 case 0xa3: am_i2p(&tms7000_device::op_and); break;
794 case 0xa4: am_i2p(&tms7000_device::op_or); break;
795 case 0xa5: am_i2p(&tms7000_device::op_xor); break;
796 case 0xa6: am_i2p(&tms7000_device::op_btjo); break;
797 case 0xa7: am_i2p(&tms7000_device::op_btjz); break;
798 case 0xa8: movd_inx(); break;
799 case 0xaa: lda_inx(); break;
800 case 0xab: sta_inx(); break;
801 case 0xac: br_inx(); break;
802 case 0xad: cmpa_inx(); break;
803 case 0xae: call_inx(); break;
804
805 case 0xb0: am_a2a(&tms7000_device::op_mov); break; // aka clrc/tsta
806 case 0xb1: am_b2a(&tms7000_device::op_mov); break; // undocumented
807 case 0xb2: am_a(&tms7000_device::op_dec); break;
808 case 0xb3: am_a(&tms7000_device::op_inc); break;
809 case 0xb4: am_a(&tms7000_device::op_inv); break;
810 case 0xb5: am_a(&tms7000_device::op_clr); break;
811 case 0xb6: am_a(&tms7000_device::op_xchb); break;
812 case 0xb7: am_a(&tms7000_device::op_swap); break;
813 case 0xb8: push_a(); break;
814 case 0xb9: pop_a(); break;
815 case 0xba: am_a(&tms7000_device::op_djnz); break;
816 case 0xbb: decd_a(); break;
817 case 0xbc: am_a(&tms7000_device::op_rr); break;
818 case 0xbd: am_a(&tms7000_device::op_rrc); break;
819 case 0xbe: am_a(&tms7000_device::op_rl); break;
820 case 0xbf: am_a(&tms7000_device::op_rlc); break;
821
822 case 0xc0: am_a2b(&tms7000_device::op_mov); break;
823 case 0xc1: am_b2b(&tms7000_device::op_mov); break; // aka tstb
824 case 0xc2: am_b(&tms7000_device::op_dec); break;
825 case 0xc3: am_b(&tms7000_device::op_inc); break;
826 case 0xc4: am_b(&tms7000_device::op_inv); break;
827 case 0xc5: am_b(&tms7000_device::op_clr); break;
828 case 0xc6: am_b(&tms7000_device::op_xchb); break; // result equivalent to tstb
829 case 0xc7: am_b(&tms7000_device::op_swap); break;
830 case 0xc8: push_b(); break;
831 case 0xc9: pop_b(); break;
832 case 0xca: am_b(&tms7000_device::op_djnz); break;
833 case 0xcb: decd_b(); break;
834 case 0xcc: am_b(&tms7000_device::op_rr); break;
835 case 0xcd: am_b(&tms7000_device::op_rrc); break;
836 case 0xce: am_b(&tms7000_device::op_rl); break;
837 case 0xcf: am_b(&tms7000_device::op_rlc); break;
838
839 case 0xd0: am_a2r(&tms7000_device::op_mov); break;
840 case 0xd1: am_b2r(&tms7000_device::op_mov); break;
841 case 0xd2: am_r(&tms7000_device::op_dec); break;
842 case 0xd3: am_r(&tms7000_device::op_inc); break;
843 case 0xd4: am_r(&tms7000_device::op_inv); break;
844 case 0xd5: am_r(&tms7000_device::op_clr); break;
845 case 0xd6: am_r(&tms7000_device::op_xchb); break;
846 case 0xd7: am_r(&tms7000_device::op_swap); break;
847 case 0xd8: push_r(); break;
848 case 0xd9: pop_r(); break;
849 case 0xda: am_r(&tms7000_device::op_djnz); break;
850 case 0xdb: decd_r(); break;
851 case 0xdc: am_r(&tms7000_device::op_rr); break;
852 case 0xdd: am_r(&tms7000_device::op_rrc); break;
853 case 0xde: am_r(&tms7000_device::op_rl); break;
854 case 0xdf: am_r(&tms7000_device::op_rlc); break;
855
856 case 0xe0: jmp(true); break;
857 case 0xe1: jmp(m_sr & SR_N); break; // jn/jlt
858 case 0xe2: jmp(m_sr & SR_Z); break; // jz/jeq
859 case 0xe3: jmp(m_sr & SR_C); break; // jc/jhs
860 case 0xe4: jmp(!(m_sr & (SR_Z | SR_N))); break; // jp/jgt
861 case 0xe5: jmp(!(m_sr & SR_N)); break; // jpz/jge - note: error in TI official documentation
862 case 0xe6: jmp(!(m_sr & SR_Z)); break; // jnz/jne
863 case 0xe7: jmp(!(m_sr & SR_C)); break; // jnc/jl
864
865 case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
866 case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
867 case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
868 trap(op << 1); break;
869
870 default: illegal(op); break;
871 }
872 }
873
execute_one(uint8_t op)874 void tms7020_exl_device::execute_one(uint8_t op)
875 {
876 // TMS7020 Exelvision EXL 100 custom opcode(s)
877 if (op == 0xd7)
878 lvdp();
879 else
880 tms7000_device::execute_one(op);
881 }
882
883
884 //-------------------------------------------------
885 // TMS70C46 specifics
886 //-------------------------------------------------
887
device_start()888 void tms70c46_device::device_start()
889 {
890 // init/zerofill
891 m_control = 0;
892
893 // register for savestates
894 save_item(NAME(m_control));
895
896 tms7000_device::device_start();
897 }
898
device_reset()899 void tms70c46_device::device_reset()
900 {
901 m_control = 0;
902
903 // reset port E
904 m_port_out_cb[4](0xff);
905
906 tms7000_device::device_reset();
907 }
908
control_r()909 uint8_t tms70c46_device::control_r()
910 {
911 return m_control;
912 }
913
control_w(uint8_t data)914 void tms70c46_device::control_w(uint8_t data)
915 {
916 // d5: enable external databus
917 if (~m_control & data & 0x20)
918 m_port_out_cb[4](0xff); // put port E into high impedance
919
920 // d4: enable clock divider when accessing slow memory (not emulated)
921 // known fast memory areas: internal ROM/RAM, system RAM
922 // known slow memory areas: system ROM, cartridge ROM/RAM
923
924 // d0-d3(all bits?): clock divider when d4 is set and address bus is in slow memory area
925 // needs to be measured, i just know that $30 is full speed, and $38 is about 4 times slower
926 m_control = data;
927 }
928
929 // DOCK-BUS: TODO..
930 // right now pretend that nothing is connected
931 // external pins are HD0-HD3(data), HSK(handshake), BAV(bus available)
932
dockbus_status_r()933 uint8_t tms70c46_device::dockbus_status_r()
934 {
935 // d0: slave _HSK
936 // d1: slave _BAV
937 // d2: unused?
938 // d3: IRQ active
939 return 0;
940 }
941
dockbus_status_w(uint8_t data)942 void tms70c46_device::dockbus_status_w(uint8_t data)
943 {
944 // d0: master _HSK (setting it low(write 1) also clears IRQ)
945 // d1: master _BAV
946 // other bits: unused?
947 }
948
dockbus_data_r()949 uint8_t tms70c46_device::dockbus_data_r()
950 {
951 return 0xff;
952 }
953
dockbus_data_w(uint8_t data)954 void tms70c46_device::dockbus_data_w(uint8_t data)
955 {
956 }
957