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