1 // license:BSD-3-Clause
2 // copyright-holders:Tony La Porta
3 	/**************************************************************************\
4 	*                 Texas Instruments TMS32010 DSP Emulator                  *
5 	*                                                                          *
6 	*                  Copyright Tony La Porta                                 *
7 	*                                                                          *
8 	*      Notes : The term 'DMA' within this document, is in reference        *
9 	*                  to Direct Memory Addressing, and NOT the usual term     *
10 	*                  of Direct Memory Access.                                *
11 	*              This is a word based microcontroller, with addressing       *
12 	*                  architecture based on the Harvard addressing scheme.    *
13 	*                                                                          *
14 	*                                                                          *
15 	*                                                                          *
16 	*  **** Change Log ****                                                    *
17 	*                                                                          *
18 	*  TLP (13-Jul-2002)                                                       *
19 	*   - Added Save-State support                                             *
20 	*   - Converted the pending_irq flag to INTF (a real flag in this device)  *
21 	*   - Fixed the ignore Interrupt Request for previous critical             *
22 	*     instructions requiring an extra instruction to be processed. For     *
23 	*     this reason, instant IRQ servicing cannot be supported here, so      *
24 	*     INTF needs to be polled within the instruction execution loop        *
25 	*   - Removed IRQ callback (IRQ ACK not supported on this device)          *
26 	*   - A pending IRQ will remain pending until it's serviced. De-asserting  *
27 	*     the IRQ Pin does not remove a pending IRQ state                      *
28 	*   - BIO is no longer treated as an IRQ line. It's polled when required.  *
29 	*     This is the true behaviour of the device                             *
30 	*   - Removed the Clear OV flag from overflow instructions. Overflow       *
31 	*     instructions can only set the flag. Flag test instructions clear it  *
32 	*   - Fixed the ABST, SUBC and SUBH instructions                           *
33 	*   - Fixed the signedness in many equation based instructions             *
34 	*   - Added the missing Previous PC to the get_register function           *
35 	*   - Changed Cycle timings to include clock ticks                         *
36 	*   - Converted some registers from ints to pairs for much cleaner code    *
37 	*  TLP (20-Jul-2002) Ver 1.10                                              *
38 	*   - Fixed the dissasembly from the debugger                              *
39 	*   - Changed all references from TMS320C10 to TMS32010                    *
40 	*  ASG (24-Sep-2002) Ver 1.20                                              *
41 	*   - Fixed overflow handling                                              *
42 	*   - Simplified logic in a few locations                                  *
43 	*  TLP (22-Feb-2004) Ver 1.21                                              *
44 	*   - Overflow for ADDH only affects upper 16bits (was modifying 32 bits)  *
45 	*   - Internal Data Memory map is assigned here now                        *
46 	*   - Cycle counts for invalid opcodes 7F1E and 7F1F are now 0             *
47 	*  RK  (23-Nov-2006) Ver 1.22                                              *
48 	*   - Fixed state of the Overflow Flag on reset                            *
49 	*   - Fixed the SUBC instruction which was incorrectly zeroing the divisor *
50 	*  TLP (13-Jul-2010) Ver 1.30                                              *
51 	*   - LST instruction was incorrectly setting an Indirect Addressing       *
52 	*     feature when Direct Addressing mode was selected                     *
53 	*   - Added TMS32015 and TMS32016 variants                                 *
54 	*  TLP (27-Jul-2010) Ver 1.31                                              *
55 	*   - Corrected cycle timing for conditional branch instructions           *
56 	*                                                                          *
57 	\**************************************************************************/
58 
59 
60 #include "emu.h"
61 #include "tms32010.h"
62 #include "32010dsm.h"
63 #include "debugger.h"
64 
65 
66 
67 #define M_RDROM(A)      TMS32010_ROM_RDMEM(A)
68 #define M_WRTROM(A,V)   TMS32010_ROM_WRMEM(A,V)
69 #define M_RDRAM(A)      TMS32010_RAM_RDMEM(A)
70 #define M_WRTRAM(A,V)   TMS32010_RAM_WRMEM(A,V)
71 #define M_RDOP(A)       TMS32010_RDOP(A)
72 #define M_RDOP_ARG(A)   TMS32010_RDOP_ARG(A)
73 #define P_IN(A)         TMS32010_In(A)
74 #define P_OUT(A,V)      TMS32010_Out(A,V)
75 
76 
77 DEFINE_DEVICE_TYPE(TMS32010, tms32010_device, "tms32010", "Texas Instruments TMS32010")
78 DEFINE_DEVICE_TYPE(TMS32015, tms32015_device, "tms32015", "Texas Instruments TMS32015")
79 DEFINE_DEVICE_TYPE(TMS32016, tms32016_device, "tms32016", "Texas Instruments TMS32016")
80 
81 
82 /****************************************************************************
83  *  TMS32010 Internal Memory Map
84  ****************************************************************************/
85 
tms32010_ram(address_map & map)86 void tms32010_device::tms32010_ram(address_map &map)
87 {
88 	map(0x00, 0x7f).ram();     /* Page 0 */
89 	map(0x80, 0x8f).ram();     /* Page 1 */
90 }
91 
92 /****************************************************************************
93  *  TMS32015/6 Internal Memory Map
94  ****************************************************************************/
95 
tms32015_ram(address_map & map)96 void tms32010_device::tms32015_ram(address_map &map)
97 {
98 	map(0x00, 0x7f).ram();     /* Page 0 */
99 	map(0x80, 0xff).ram();     /* Page 1 */
100 }
101 
102 
tms32010_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)103 tms32010_device::tms32010_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
104 	: tms32010_device(mconfig, TMS32010, tag, owner, clock, address_map_constructor(FUNC(tms32010_device::tms32010_ram), this), 0x0fff)
105 {
106 }
107 
108 
tms32010_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock,address_map_constructor data_map,int addr_mask)109 tms32010_device::tms32010_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor data_map, int addr_mask)
110 	: cpu_device(mconfig, type, tag, owner, clock)
111 	, m_program_config("program", ENDIANNESS_BIG, 16, 12, -1)
112 	, m_data_config("data", ENDIANNESS_BIG, 16, 8, -1, data_map)
113 	, m_io_config("io", ENDIANNESS_BIG, 16, 4, -1)
114 	, m_bio_in(*this)
115 	, m_addr_mask(addr_mask)
116 {
117 }
118 
119 
tms32015_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)120 tms32015_device::tms32015_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
121 	: tms32010_device(mconfig, TMS32015, tag, owner, clock, address_map_constructor(FUNC(tms32015_device::tms32015_ram), this), 0x0fff)
122 {
123 }
124 
125 
tms32016_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)126 tms32016_device::tms32016_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
127 	: tms32010_device(mconfig, TMS32016, tag, owner, clock, address_map_constructor(FUNC(tms32016_device::tms32015_ram), this), 0xffff)
128 {
129 }
130 
memory_space_config() const131 device_memory_interface::space_config_vector tms32010_device::memory_space_config() const
132 {
133 	return space_config_vector {
134 		std::make_pair(AS_PROGRAM, &m_program_config),
135 		std::make_pair(AS_DATA,    &m_data_config),
136 		std::make_pair(AS_IO,      &m_io_config)
137 	};
138 }
139 
create_disassembler()140 std::unique_ptr<util::disasm_interface> tms32010_device::create_disassembler()
141 {
142 	return std::make_unique<tms32010_disassembler>();
143 }
144 
145 
146 /*********  The following is the Status (Flag) register definition.  *********/
147 /* 15 | 14  |  13  | 12 | 11 | 10 | 9 |  8  | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0  */
148 /* OV | OVM | INTM |  1 |  1 |  1 | 1 | ARP | 1 | 1 | 1 | 1 | 1 | 1 | 1 | DP */
149 #define OV_FLAG     0x8000  /* OV   (Overflow flag) 1 indicates an overflow */
150 #define OVM_FLAG    0x4000  /* OVM  (Overflow Mode bit) 1 forces ACC overflow to greatest positive or negative saturation value */
151 #define INTM_FLAG   0x2000  /* INTM (Interrupt Mask flag) 0 enables maskable interrupts */
152 #define ARP_REG     0x0100  /* ARP  (Auxiliary Register Pointer) */
153 #define DP_REG      0x0001  /* DP   (Data memory Pointer (bank) bit) */
154 
155 #define OV      ( m_STR & OV_FLAG)          /* OV   (Overflow flag) */
156 #define OVM     ( m_STR & OVM_FLAG)         /* OVM  (Overflow Mode bit) 1 indicates an overflow */
157 #define INTM    ( m_STR & INTM_FLAG)        /* INTM (Interrupt enable flag) 0 enables maskable interrupts */
158 #define ARP     ((m_STR & ARP_REG) >> 8)    /* ARP  (Auxiliary Register Pointer) */
159 #define DP      ((m_STR & DP_REG) << 7)     /* DP   (Data memory Pointer bit) */
160 
161 #define DMA_DP  (DP | (m_opcode.b.l & 0x7f))    /* address used in direct memory access operations */
162 #define DMA_DP1 (0x80 | m_opcode.b.l)           /* address used in direct memory access operations for sst instruction */
163 #define IND     (m_AR[ARP] & 0xff)              /* address used in indirect memory access operations */
164 
165 
166 /****************************************************************************
167  *  Input a word from given I/O port
168  */
169 
170 #define TMS32010_In(Port) (m_io.read_word(Port))
171 
172 
173 /****************************************************************************
174  *  Output a word to given I/O port
175  */
176 
177 #define TMS32010_Out(Port,Value) (m_io.write_word(Port,Value))
178 
179 
180 
181 /****************************************************************************
182  *  Read a word from given ROM memory location
183  */
184 
185 #define TMS32010_ROM_RDMEM(A) (m_program.read_word(A))
186 
187 
188 /****************************************************************************
189  *  Write a word to given ROM memory location
190  */
191 
192 #define TMS32010_ROM_WRMEM(A,V) (m_program.write_word(A,V))
193 
194 
195 
196 /****************************************************************************
197  *  Read a word from given RAM memory location
198  */
199 
200 #define TMS32010_RAM_RDMEM(A) (m_data.read_word(A))
201 
202 
203 /****************************************************************************
204  *  Write a word to given RAM memory location
205  */
206 
207 #define TMS32010_RAM_WRMEM(A,V) (m_data.write_word(A,V))
208 
209 
210 
211 /****************************************************************************
212  *  TMS32010_RDOP() is identical to TMS32010_RDMEM() except it is used for reading
213  *  opcodes. In case of system with memory mapped I/O, this function can be
214  *  used to greatly speed up emulation
215  */
216 
217 #define TMS32010_RDOP(A) (m_cache.read_word(A))
218 
219 
220 /****************************************************************************
221  *  TMS32010_RDOP_ARG() is identical to TMS32010_RDOP() except it is used
222  *  for reading opcode arguments. This difference can be used to support systems
223  *  that use different encoding mechanisms for opcodes and opcode arguments
224  */
225 
226 #define TMS32010_RDOP_ARG(A) (m_cache.read_word(A))
227 
228 
229 /************************************************************************
230  *  Shortcuts
231  ************************************************************************/
232 
CLR(uint16_t flag)233 void tms32010_device::CLR(uint16_t flag) { m_STR &= ~flag; m_STR |= 0x1efe; }
SET_FLAG(uint16_t flag)234 void tms32010_device::SET_FLAG(uint16_t flag) { m_STR |=  flag; m_STR |= 0x1efe; }
235 
236 
CALCULATE_ADD_OVERFLOW(int32_t addval)237 void tms32010_device::CALCULATE_ADD_OVERFLOW(int32_t addval)
238 {
239 	if ((int32_t)(~(m_oldacc.d ^ addval) & (m_oldacc.d ^ m_ACC.d)) < 0) {
240 		SET_FLAG(OV_FLAG);
241 		if (OVM)
242 			m_ACC.d = ((int32_t)m_oldacc.d < 0) ? 0x80000000 : 0x7fffffff;
243 	}
244 }
CALCULATE_SUB_OVERFLOW(int32_t subval)245 void tms32010_device::CALCULATE_SUB_OVERFLOW(int32_t subval)
246 {
247 	if ((int32_t)((m_oldacc.d ^ subval) & (m_oldacc.d ^ m_ACC.d)) < 0) {
248 		SET_FLAG(OV_FLAG);
249 		if (OVM)
250 			m_ACC.d = ((int32_t)m_oldacc.d < 0) ? 0x80000000 : 0x7fffffff;
251 	}
252 }
253 
POP_STACK()254 uint16_t tms32010_device::POP_STACK()
255 {
256 	uint16_t data = m_STACK[3];
257 	m_STACK[3] = m_STACK[2];
258 	m_STACK[2] = m_STACK[1];
259 	m_STACK[1] = m_STACK[0];
260 	return (data & m_addr_mask);
261 }
PUSH_STACK(uint16_t data)262 void tms32010_device::PUSH_STACK(uint16_t data)
263 {
264 	m_STACK[0] = m_STACK[1];
265 	m_STACK[1] = m_STACK[2];
266 	m_STACK[2] = m_STACK[3];
267 	m_STACK[3] = (data & m_addr_mask);
268 }
269 
UPDATE_AR()270 void tms32010_device::UPDATE_AR()
271 {
272 	if (m_opcode.b.l & 0x30) {
273 		uint16_t tmpAR = m_AR[ARP];
274 		if (m_opcode.b.l & 0x20) tmpAR++ ;
275 		if (m_opcode.b.l & 0x10) tmpAR-- ;
276 		m_AR[ARP] = (m_AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
277 	}
278 }
UPDATE_ARP()279 void tms32010_device::UPDATE_ARP()
280 {
281 	if (~m_opcode.b.l & 0x08) {
282 		if (m_opcode.b.l & 0x01) SET_FLAG(ARP_REG);
283 		else CLR(ARP_REG);
284 	}
285 }
286 
287 
getdata(uint8_t shift,uint8_t signext)288 void tms32010_device::getdata(uint8_t shift,uint8_t signext)
289 {
290 	if (m_opcode.b.l & 0x80)
291 		m_memaccess = IND;
292 	else
293 		m_memaccess = DMA_DP;
294 
295 	m_ALU.d = (uint16_t)M_RDRAM(m_memaccess);
296 	if (signext) m_ALU.d = (int16_t)m_ALU.d;
297 	m_ALU.d <<= shift;
298 	if (m_opcode.b.l & 0x80) {
299 		UPDATE_AR();
300 		UPDATE_ARP();
301 	}
302 }
303 
putdata(uint16_t data)304 void tms32010_device::putdata(uint16_t data)
305 {
306 	if (m_opcode.b.l & 0x80)
307 		m_memaccess = IND;
308 	else
309 		m_memaccess = DMA_DP;
310 
311 	if (m_opcode.b.l & 0x80) {
312 		UPDATE_AR();
313 		UPDATE_ARP();
314 	}
315 	M_WRTRAM(m_memaccess,data);
316 }
putdata_sar(uint8_t data)317 void tms32010_device::putdata_sar(uint8_t data)
318 {
319 	if (m_opcode.b.l & 0x80)
320 		m_memaccess = IND;
321 	else
322 		m_memaccess = DMA_DP;
323 
324 	if (m_opcode.b.l & 0x80) {
325 		UPDATE_AR();
326 		UPDATE_ARP();
327 	}
328 	M_WRTRAM(m_memaccess,m_AR[data]);
329 }
putdata_sst(uint16_t data)330 void tms32010_device::putdata_sst(uint16_t data)
331 {
332 	if (m_opcode.b.l & 0x80)
333 		m_memaccess = IND;
334 	else
335 		m_memaccess = DMA_DP1;  /* Page 1 only */
336 
337 	if (m_opcode.b.l & 0x80) {
338 		UPDATE_AR();
339 	}
340 	M_WRTRAM(m_memaccess,data);
341 }
342 
343 
344 
345 /************************************************************************
346  *  Emulate the Instructions
347  ************************************************************************/
348 
349 /* This following function is here to fill in the void for */
350 /* the opcode call function. This function is never called. */
351 
opcodes_7F()352 void tms32010_device::opcodes_7F()  { fatalerror("Should never get here!\n"); }
353 
354 
illegal()355 void tms32010_device::illegal()
356 {
357 	logerror("TMS32010:  PC=%04x,  Illegal opcode = %04x\n", (m_PC-1), m_opcode.w.l);
358 }
359 
abst()360 void tms32010_device::abst()
361 {
362 	if ( (int32_t)(m_ACC.d) < 0 ) {
363 		m_ACC.d = -m_ACC.d;
364 		if (OVM && (m_ACC.d == 0x80000000)) m_ACC.d-- ;
365 	}
366 }
367 
368 /*** The manual doesn't mention overflow with the ADD? instructions however ***
369  *** overflow is implemented here, because it makes little sense otherwise ****
370  *** while newer generations of this type of chip supported it. The ***********
371  *** manual may be wrong wrong (apart from other errors the manual has). ******
372 
373 void tms32010_device::add_sh()    { getdata(m_opcode.b.h,1); m_ACC.d += m_ALU.d; }
374 void tms32010_device::addh()      { getdata(0,0); m_ACC.d += (m_ALU.d << 16); }
375  ***/
376 
add_sh()377 void tms32010_device::add_sh()
378 {
379 	m_oldacc.d = m_ACC.d;
380 	getdata((m_opcode.b.h & 0xf),1);
381 	m_ACC.d += m_ALU.d;
382 	CALCULATE_ADD_OVERFLOW(m_ALU.d);
383 }
addh()384 void tms32010_device::addh()
385 {
386 	m_oldacc.d = m_ACC.d;
387 	getdata(0,0);
388 	m_ACC.w.h += m_ALU.w.l;
389 	if ((int16_t)(~(m_oldacc.w.h ^ m_ALU.w.h) & (m_oldacc.w.h ^ m_ACC.w.h)) < 0) {
390 		SET_FLAG(OV_FLAG);
391 		if (OVM)
392 			m_ACC.w.h = ((int16_t)m_oldacc.w.h < 0) ? 0x8000 : 0x7fff;
393 	}
394 }
adds()395 void tms32010_device::adds()
396 {
397 	m_oldacc.d = m_ACC.d;
398 	getdata(0,0);
399 	m_ACC.d += m_ALU.d;
400 	CALCULATE_ADD_OVERFLOW(m_ALU.d);
401 }
and_()402 void tms32010_device::and_()
403 {
404 	getdata(0,0);
405 	m_ACC.d &= m_ALU.d;
406 }
apac()407 void tms32010_device::apac()
408 {
409 	m_oldacc.d = m_ACC.d;
410 	m_ACC.d += m_Preg.d;
411 	CALCULATE_ADD_OVERFLOW(m_Preg.d);
412 }
br()413 void tms32010_device::br()
414 {
415 	m_PC = M_RDOP_ARG(m_PC);
416 }
banz()417 void tms32010_device::banz()
418 {
419 	if (m_AR[ARP] & 0x01ff) {
420 		m_PC = M_RDOP_ARG(m_PC);
421 		m_icount -= add_branch_cycle();
422 	}
423 	else
424 		m_PC++ ;
425 	m_ALU.w.l = m_AR[ARP];
426 	m_ALU.w.l-- ;
427 	m_AR[ARP] = (m_AR[ARP] & 0xfe00) | (m_ALU.w.l & 0x01ff);
428 }
bgez()429 void tms32010_device::bgez()
430 {
431 	if ( (int32_t)(m_ACC.d) >= 0 ) {
432 		m_PC = M_RDOP_ARG(m_PC);
433 		m_icount -= add_branch_cycle();
434 	}
435 	else
436 		m_PC++ ;
437 }
bgz()438 void tms32010_device::bgz()
439 {
440 	if ( (int32_t)(m_ACC.d) > 0 ) {
441 		m_PC = M_RDOP_ARG(m_PC);
442 		m_icount -= add_branch_cycle();
443 	}
444 	else
445 		m_PC++ ;
446 }
bioz()447 void tms32010_device::bioz()
448 {
449 	if (m_bio_in() != CLEAR_LINE) {
450 		m_PC = M_RDOP_ARG(m_PC);
451 		m_icount -= add_branch_cycle();
452 	}
453 	else
454 		m_PC++ ;
455 }
blez()456 void tms32010_device::blez()
457 {
458 	if ( (int32_t)(m_ACC.d) <= 0 ) {
459 		m_PC = M_RDOP_ARG(m_PC);
460 		m_icount -= add_branch_cycle();
461 	}
462 	else
463 		m_PC++ ;
464 }
blz()465 void tms32010_device::blz()
466 {
467 	if ( (int32_t)(m_ACC.d) <  0 ) {
468 		m_PC = M_RDOP_ARG(m_PC);
469 		m_icount -= add_branch_cycle();
470 	}
471 	else
472 		m_PC++ ;
473 }
bnz()474 void tms32010_device::bnz()
475 {
476 	if (m_ACC.d != 0) {
477 		m_PC = M_RDOP_ARG(m_PC);
478 		m_icount -= add_branch_cycle();
479 	}
480 	else
481 		m_PC++ ;
482 }
bv()483 void tms32010_device::bv()
484 {
485 	if (OV) {
486 		CLR(OV_FLAG);
487 		m_PC = M_RDOP_ARG(m_PC);
488 		m_icount -= add_branch_cycle();
489 	}
490 	else
491 		m_PC++ ;
492 }
bz()493 void tms32010_device::bz()
494 {
495 	if (m_ACC.d == 0) {
496 		m_PC = M_RDOP_ARG(m_PC);
497 		m_icount -= add_branch_cycle();
498 	}
499 	else
500 		m_PC++ ;
501 }
cala()502 void tms32010_device::cala()
503 {
504 	PUSH_STACK(m_PC);
505 	m_PC = m_ACC.w.l & m_addr_mask;
506 }
call()507 void tms32010_device::call()
508 {
509 	m_PC++ ;
510 	PUSH_STACK(m_PC);
511 	m_PC = M_RDOP_ARG((m_PC - 1));
512 }
dint()513 void tms32010_device::dint()
514 {
515 	SET_FLAG(INTM_FLAG);
516 }
dmov()517 void tms32010_device::dmov()
518 {
519 	getdata(0,0);
520 	M_WRTRAM((m_memaccess + 1),m_ALU.w.l);
521 }
eint()522 void tms32010_device::eint()
523 {
524 	CLR(INTM_FLAG);
525 }
in_p()526 void tms32010_device::in_p()
527 {
528 	m_ALU.w.l = P_IN(m_opcode.b.h & 7);
529 	putdata(m_ALU.w.l);
530 }
lac_sh()531 void tms32010_device::lac_sh()
532 {
533 	getdata((m_opcode.b.h & 0x0f),1);
534 	m_ACC.d = m_ALU.d;
535 }
lack()536 void tms32010_device::lack()
537 {
538 	m_ACC.d = m_opcode.b.l;
539 }
lar_ar0()540 void tms32010_device::lar_ar0()
541 {
542 	getdata(0,0);
543 	m_AR[0] = m_ALU.w.l;
544 }
lar_ar1()545 void tms32010_device::lar_ar1()
546 {
547 	getdata(0,0);
548 	m_AR[1] = m_ALU.w.l;
549 }
lark_ar0()550 void tms32010_device::lark_ar0()
551 {
552 	m_AR[0] = m_opcode.b.l;
553 }
lark_ar1()554 void tms32010_device::lark_ar1()
555 {
556 	m_AR[1] = m_opcode.b.l;
557 }
larp_mar()558 void tms32010_device::larp_mar()
559 {
560 	if (m_opcode.b.l & 0x80) {
561 		UPDATE_AR();
562 		UPDATE_ARP();
563 	}
564 }
ldp()565 void tms32010_device::ldp()
566 {
567 	getdata(0,0);
568 	if (m_ALU.d & 1)
569 		SET_FLAG(DP_REG);
570 	else
571 		CLR(DP_REG);
572 }
ldpk()573 void tms32010_device::ldpk()
574 {
575 	if (m_opcode.b.l & 1)
576 		SET_FLAG(DP_REG);
577 	else
578 		CLR(DP_REG);
579 }
lst()580 void tms32010_device::lst()
581 {
582 	if (m_opcode.b.l & 0x80) {
583 		m_opcode.b.l |= 0x08; /* In Indirect Addressing mode, next ARP is not supported here so mask it */
584 	}
585 	getdata(0,0);
586 	m_ALU.w.l &= (~INTM_FLAG);  /* Must not affect INTM */
587 	m_STR &= INTM_FLAG;
588 	m_STR |= m_ALU.w.l;
589 	m_STR |= 0x1efe;
590 }
lt()591 void tms32010_device::lt()
592 {
593 	getdata(0,0);
594 	m_Treg = m_ALU.w.l;
595 }
lta()596 void tms32010_device::lta()
597 {
598 	m_oldacc.d = m_ACC.d;
599 	getdata(0,0);
600 	m_Treg = m_ALU.w.l;
601 	m_ACC.d += m_Preg.d;
602 	CALCULATE_ADD_OVERFLOW(m_Preg.d);
603 }
ltd()604 void tms32010_device::ltd()
605 {
606 	m_oldacc.d = m_ACC.d;
607 	getdata(0,0);
608 	m_Treg = m_ALU.w.l;
609 	M_WRTRAM((m_memaccess + 1),m_ALU.w.l);
610 	m_ACC.d += m_Preg.d;
611 	CALCULATE_ADD_OVERFLOW(m_Preg.d);
612 }
mpy()613 void tms32010_device::mpy()
614 {
615 	getdata(0,0);
616 	m_Preg.d = (int16_t)m_ALU.w.l * (int16_t)m_Treg;
617 	if (m_Preg.d == 0x40000000) m_Preg.d = 0xc0000000;
618 }
mpyk()619 void tms32010_device::mpyk()
620 {
621 	m_Preg.d = (int16_t)m_Treg * ((int16_t)(m_opcode.w.l << 3) >> 3);
622 }
nop()623 void tms32010_device::nop()
624 {
625 	/* Nothing to do */
626 }
or_()627 void tms32010_device::or_()
628 {
629 	getdata(0,0);
630 	m_ACC.w.l |= m_ALU.w.l;
631 }
out_p()632 void tms32010_device::out_p()
633 {
634 	getdata(0,0);
635 	P_OUT( (m_opcode.b.h & 7), m_ALU.w.l );
636 }
pac()637 void tms32010_device::pac()
638 {
639 	m_ACC.d = m_Preg.d;
640 }
pop()641 void tms32010_device::pop()
642 {
643 	m_ACC.w.l = POP_STACK();
644 	m_ACC.w.h = 0x0000;
645 }
push()646 void tms32010_device::push()
647 {
648 	PUSH_STACK(m_ACC.w.l);
649 }
ret()650 void tms32010_device::ret()
651 {
652 	m_PC = POP_STACK();
653 }
rovm()654 void tms32010_device::rovm()
655 {
656 	CLR(OVM_FLAG);
657 }
sach_sh()658 void tms32010_device::sach_sh()
659 {
660 	m_ALU.d = (m_ACC.d << (m_opcode.b.h & 7));
661 	putdata(m_ALU.w.h);
662 }
sacl()663 void tms32010_device::sacl()
664 {
665 	putdata(m_ACC.w.l);
666 }
sar_ar0()667 void tms32010_device::sar_ar0()
668 {
669 	putdata_sar(0);
670 }
sar_ar1()671 void tms32010_device::sar_ar1()
672 {
673 	putdata_sar(1);
674 }
sovm()675 void tms32010_device::sovm()
676 {
677 	SET_FLAG(OVM_FLAG);
678 }
spac()679 void tms32010_device::spac()
680 {
681 	m_oldacc.d = m_ACC.d;
682 	m_ACC.d -= m_Preg.d;
683 	CALCULATE_SUB_OVERFLOW(m_Preg.d);
684 }
sst()685 void tms32010_device::sst()
686 {
687 	putdata_sst(m_STR);
688 }
sub_sh()689 void tms32010_device::sub_sh()
690 {
691 	m_oldacc.d = m_ACC.d;
692 	getdata((m_opcode.b.h & 0x0f),1);
693 	m_ACC.d -= m_ALU.d;
694 	CALCULATE_SUB_OVERFLOW(m_ALU.d);
695 }
subc()696 void tms32010_device::subc()
697 {
698 	m_oldacc.d = m_ACC.d;
699 	getdata(15,0);
700 	m_ALU.d = (int32_t) m_ACC.d - m_ALU.d;
701 	if ((int32_t)((m_oldacc.d ^ m_ALU.d) & (m_oldacc.d ^ m_ACC.d)) < 0)
702 		SET_FLAG(OV_FLAG);
703 	if ( (int32_t)(m_ALU.d) >= 0 )
704 		m_ACC.d = ((m_ALU.d << 1) + 1);
705 	else
706 		m_ACC.d = (m_ACC.d << 1);
707 }
subh()708 void tms32010_device::subh()
709 {
710 	m_oldacc.d = m_ACC.d;
711 	getdata(16,0);
712 	m_ACC.d -= m_ALU.d;
713 	CALCULATE_SUB_OVERFLOW(m_ALU.d);
714 }
subs()715 void tms32010_device::subs()
716 {
717 	m_oldacc.d = m_ACC.d;
718 	getdata(0,0);
719 	m_ACC.d -= m_ALU.d;
720 	CALCULATE_SUB_OVERFLOW(m_ALU.d);
721 }
tblr()722 void tms32010_device::tblr()
723 {
724 	m_ALU.d = M_RDROM((m_ACC.w.l & m_addr_mask));
725 	putdata(m_ALU.w.l);
726 	m_STACK[0] = m_STACK[1];
727 }
tblw()728 void tms32010_device::tblw()
729 {
730 	getdata(0,0);
731 	M_WRTROM(((m_ACC.w.l & m_addr_mask)),m_ALU.w.l);
732 	m_STACK[0] = m_STACK[1];
733 }
xor_()734 void tms32010_device::xor_()
735 {
736 	getdata(0,0);
737 	m_ACC.w.l ^= m_ALU.w.l;
738 }
zac()739 void tms32010_device::zac()
740 {
741 	m_ACC.d = 0;
742 }
zalh()743 void tms32010_device::zalh()
744 {
745 	getdata(0,0);
746 	m_ACC.w.h = m_ALU.w.l;
747 	m_ACC.w.l = 0x0000;
748 }
zals()749 void tms32010_device::zals()
750 {
751 	getdata(0,0);
752 	m_ACC.w.l = m_ALU.w.l;
753 	m_ACC.w.h = 0x0000;
754 }
755 
756 
757 
758 /***********************************************************************
759  *  Opcode Table (Cycles, Instruction)
760  ***********************************************************************/
761 
762 /* Conditional Branch instructions take two cycles when the test condition is met and the branch performed */
763 
764 const tms32010_device::tms32010_opcode tms32010_device::s_opcode_main[256]=
765 {
766 /*00*/  {1, &tms32010_device::add_sh  },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },
767 /*08*/  {1, &tms32010_device::add_sh  },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },{1, &tms32010_device::add_sh    },
768 /*10*/  {1, &tms32010_device::sub_sh  },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },
769 /*18*/  {1, &tms32010_device::sub_sh  },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },{1, &tms32010_device::sub_sh    },
770 /*20*/  {1, &tms32010_device::lac_sh  },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },
771 /*28*/  {1, &tms32010_device::lac_sh  },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },{1, &tms32010_device::lac_sh    },
772 /*30*/  {1, &tms32010_device::sar_ar0 },{1, &tms32010_device::sar_ar1   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
773 /*38*/  {1, &tms32010_device::lar_ar0 },{1, &tms32010_device::lar_ar1   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
774 /*40*/  {2, &tms32010_device::in_p    },{2, &tms32010_device::in_p      },{2, &tms32010_device::in_p      },{2, &tms32010_device::in_p      },{2, &tms32010_device::in_p      },{2, &tms32010_device::in_p      },{2, &tms32010_device::in_p      },{2, &tms32010_device::in_p      },
775 /*48*/  {2, &tms32010_device::out_p   },{2, &tms32010_device::out_p     },{2, &tms32010_device::out_p     },{2, &tms32010_device::out_p     },{2, &tms32010_device::out_p     },{2, &tms32010_device::out_p     },{2, &tms32010_device::out_p     },{2, &tms32010_device::out_p     },
776 /*50*/  {1, &tms32010_device::sacl    },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
777 /*58*/  {1, &tms32010_device::sach_sh },{1, &tms32010_device::sach_sh   },{1, &tms32010_device::sach_sh   },{1, &tms32010_device::sach_sh   },{1, &tms32010_device::sach_sh   },{1, &tms32010_device::sach_sh   },{1, &tms32010_device::sach_sh   },{1, &tms32010_device::sach_sh   },
778 /*60*/  {1, &tms32010_device::addh    },{1, &tms32010_device::adds      },{1, &tms32010_device::subh      },{1, &tms32010_device::subs      },{1, &tms32010_device::subc      },{1, &tms32010_device::zalh      },{1, &tms32010_device::zals      },{3, &tms32010_device::tblr      },
779 /*68*/  {1, &tms32010_device::larp_mar},{1, &tms32010_device::dmov      },{1, &tms32010_device::lt        },{1, &tms32010_device::ltd       },{1, &tms32010_device::lta       },{1, &tms32010_device::mpy       },{1, &tms32010_device::ldpk      },{1, &tms32010_device::ldp       },
780 /*70*/  {1, &tms32010_device::lark_ar0},{1, &tms32010_device::lark_ar1  },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
781 /*78*/  {1, &tms32010_device::xor_    },{1, &tms32010_device::and_      },{1, &tms32010_device::or_       },{1, &tms32010_device::lst       },{1, &tms32010_device::sst       },{3, &tms32010_device::tblw      },{1, &tms32010_device::lack      },{0, &tms32010_device::opcodes_7F    },
782 /*80*/  {1, &tms32010_device::mpyk    },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },
783 /*88*/  {1, &tms32010_device::mpyk    },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },
784 /*90*/  {1, &tms32010_device::mpyk    },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },
785 /*98*/  {1, &tms32010_device::mpyk    },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },{1, &tms32010_device::mpyk      },
786 /*A0*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
787 /*A8*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
788 /*B0*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
789 /*B8*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
790 /*C0*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
791 /*C8*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
792 /*D0*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
793 /*D8*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
794 /*E0*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
795 /*E8*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
796 /*F0*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{1, &tms32010_device::banz      },{1, &tms32010_device::bv        },{1, &tms32010_device::bioz      },{0, &tms32010_device::illegal   },
797 /*F8*/  {2, &tms32010_device::call    },{2, &tms32010_device::br        },{1, &tms32010_device::blz       },{1, &tms32010_device::blez      },{1, &tms32010_device::bgz       },{1, &tms32010_device::bgez      },{1, &tms32010_device::bnz       },{1, &tms32010_device::bz        }
798 };
799 
800 const tms32010_device::tms32010_opcode tms32010_device::s_opcode_7F[32]=
801 {
802 /*80*/  {1, &tms32010_device::nop     },{1, &tms32010_device::dint      },{1, &tms32010_device::eint      },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
803 /*88*/  {1, &tms32010_device::abst    },{1, &tms32010_device::zac       },{1, &tms32010_device::rovm      },{1, &tms32010_device::sovm      },{2, &tms32010_device::cala      },{2, &tms32010_device::ret       },{1, &tms32010_device::pac       },{1, &tms32010_device::apac      },
804 /*90*/  {1, &tms32010_device::spac    },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },
805 /*98*/  {0, &tms32010_device::illegal },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   },{2, &tms32010_device::push      },{2, &tms32010_device::pop       },{0, &tms32010_device::illegal   },{0, &tms32010_device::illegal   }
806 };
807 
add_branch_cycle()808 int tms32010_device::add_branch_cycle()
809 {
810 	return s_opcode_main[m_opcode.b.h].cycles;
811 }
812 
813 /****************************************************************************
814  *  Inits CPU emulation
815  ****************************************************************************/
816 
device_start()817 void tms32010_device::device_start()
818 {
819 	save_item(NAME(m_PC));
820 	save_item(NAME(m_PREVPC));
821 	save_item(NAME(m_STR));
822 	save_item(NAME(m_ACC.d));
823 	save_item(NAME(m_ALU.d));
824 	save_item(NAME(m_Preg.d));
825 	save_item(NAME(m_Treg));
826 	save_item(NAME(m_AR[0]));
827 	save_item(NAME(m_AR[1]));
828 	save_item(NAME(m_STACK[0]));
829 	save_item(NAME(m_STACK[1]));
830 	save_item(NAME(m_STACK[2]));
831 	save_item(NAME(m_STACK[3]));
832 	save_item(NAME(m_INTF));
833 	save_item(NAME(m_opcode.d));
834 	save_item(NAME(m_oldacc.d));
835 	save_item(NAME(m_memaccess));
836 	save_item(NAME(m_addr_mask));
837 
838 	space(AS_PROGRAM).cache(m_cache);
839 	space(AS_PROGRAM).specific(m_program);
840 	space(AS_DATA).specific(m_data);
841 	space(AS_IO).specific(m_io);
842 
843 	m_bio_in.resolve_safe(0);
844 
845 	m_PREVPC = 0;
846 	m_ALU.d = 0;
847 	m_Preg.d = 0;
848 	m_Treg = 0;
849 	m_AR[0] = m_AR[1] = 0;
850 	m_STACK[0] = m_STACK[1] = m_STACK[2] = m_STACK[3] = 0;
851 	m_opcode.d = 0;
852 	m_oldacc.d = 0;
853 	m_memaccess = 0;
854 	m_PC = 0;
855 	m_STR = 0;
856 	m_ACC.d = 0;
857 
858 	state_add( TMS32010_PC,   "PC",   m_PC).formatstr("%04X");
859 	state_add( TMS32010_STR,  "STR",  m_STR).formatstr("%04X");
860 	state_add( TMS32010_ACC,  "ACC",  m_ACC.d).formatstr("%08X");
861 	state_add( TMS32010_PREG, "P",    m_Preg.d).formatstr("%08X");
862 	state_add( TMS32010_TREG, "T",    m_Treg).formatstr("%04X");
863 	state_add( TMS32010_AR0,  "AR0",  m_AR[0]).formatstr("%04X");
864 	state_add( TMS32010_AR1,  "AR1",  m_AR[1]).formatstr("%04X");
865 	state_add( TMS32010_STK0, "STK0", m_STACK[0]).formatstr("%04X");
866 	state_add( TMS32010_STK1, "STK1", m_STACK[1]).formatstr("%04X");
867 	state_add( TMS32010_STK2, "STK2", m_STACK[2]).formatstr("%04X");
868 	state_add( TMS32010_STK3, "STK3", m_STACK[3]).formatstr("%04X");
869 
870 	state_add(STATE_GENPC, "GENPC", m_PC).formatstr("%04X").noshow();
871 	state_add(STATE_GENPCBASE, "CURPC", m_PREVPC).formatstr("%04X").noshow();
872 	/* This is actually not a stack pointer, but the stack contents */
873 	state_add(STATE_GENSP, "GENSP", m_STACK[3]).formatstr("%04X").noshow();
874 	state_add(STATE_GENFLAGS, "GENFLAGS",  m_STR).formatstr("%16s").noshow();
875 
876 	set_icountptr(m_icount);
877 }
878 
879 
880 /****************************************************************************
881  *  TMS32010 Reset registers to their initial values
882  ****************************************************************************/
883 
device_reset()884 void tms32010_device::device_reset()
885 {
886 	m_PC    = 0;
887 	m_ACC.d = 0;
888 	m_INTF  = TMS32010_INT_NONE;
889 	/* Setup Status Register : 7efe */
890 	CLR((OV_FLAG | ARP_REG | DP_REG));
891 	SET_FLAG((OVM_FLAG | INTM_FLAG));
892 }
893 
894 
state_string_export(const device_state_entry & entry,std::string & str) const895 void tms32010_device::state_string_export(const device_state_entry &entry, std::string &str) const
896 {
897 	switch (entry.index())
898 	{
899 		case STATE_GENFLAGS:
900 			str = string_format("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
901 				m_STR & 0x8000 ? 'O':'.',
902 				m_STR & 0x4000 ? 'M':'.',
903 				m_STR & 0x2000 ? 'I':'.',
904 				m_STR & 0x1000 ? '.':'?',
905 				m_STR & 0x0800 ? 'a':'?',
906 				m_STR & 0x0400 ? 'r':'?',
907 				m_STR & 0x0200 ? 'p':'?',
908 				m_STR & 0x0100 ? '1':'0',
909 				m_STR & 0x0080 ? '.':'?',
910 				m_STR & 0x0040 ? '.':'?',
911 				m_STR & 0x0020 ? '.':'?',
912 				m_STR & 0x0010 ? '.':'?',
913 				m_STR & 0x0008 ? '.':'?',
914 				m_STR & 0x0004 ? 'd':'?',
915 				m_STR & 0x0002 ? 'p':'?',
916 				m_STR & 0x0001 ? '1':'0'
917 			);
918 			break;
919 	}
920 }
921 
922 
923 /****************************************************************************
924  *  Set IRQ line state
925  ****************************************************************************/
926 
execute_set_input(int irqline,int state)927 void tms32010_device::execute_set_input(int irqline, int state)
928 {
929 	/* Pending Interrupts cannot be cleared! */
930 	if (state == ASSERT_LINE) m_INTF |= TMS32010_INT_PENDING;
931 }
932 
933 
934 
935 /****************************************************************************
936  *  Issue an interrupt if necessary
937  ****************************************************************************/
938 
Ext_IRQ()939 int tms32010_device::Ext_IRQ()
940 {
941 	if (INTM == 0)
942 	{
943 		logerror("TMS32010:  EXT INTERRUPT\n");
944 		m_INTF = TMS32010_INT_NONE;
945 		SET_FLAG(INTM_FLAG);
946 		PUSH_STACK(m_PC);
947 		m_PC = 0x0002;
948 		return (s_opcode_7F[0x1c].cycles + s_opcode_7F[0x01].cycles);   /* 3 cycles used due to PUSH and DINT operation ? */
949 	}
950 	return (0);
951 }
952 
953 
954 /****************************************************************************
955  *  Execute IPeriod. Return 0 if emulation should be stopped
956  ****************************************************************************/
957 
execute_run()958 void tms32010_device::execute_run()
959 {
960 	do
961 	{
962 		if (m_INTF) {
963 			/* Dont service INT if previous instruction was MPY, MPYK or EINT */
964 			if ((m_opcode.b.h != 0x6d) && ((m_opcode.b.h & 0xe0) != 0x80) && (m_opcode.w.l != 0x7f82))
965 				m_icount -= Ext_IRQ();
966 		}
967 
968 		m_PREVPC = m_PC;
969 
970 		debugger_instruction_hook(m_PC);
971 
972 		m_opcode.d = M_RDOP(m_PC);
973 		m_PC++;
974 
975 		if (m_opcode.b.h != 0x7f)   { /* Do all opcodes except the 7Fxx ones */
976 			m_icount -= s_opcode_main[m_opcode.b.h].cycles;
977 			(this->*s_opcode_main[m_opcode.b.h].function)();
978 		}
979 		else { /* Opcode major byte 7Fxx has many opcodes in its minor byte */
980 			m_icount -= s_opcode_7F[(m_opcode.b.l & 0x1f)].cycles;
981 			(this->*s_opcode_7F[(m_opcode.b.l & 0x1f)].function)();
982 		}
983 	} while (m_icount > 0);
984 }
985