1  /**************************************************************************\
2  *                 Texas Instruments TMS32010 DSP Emulator                  *
3  *                                                                          *
4  *                  Copyright (C) 1999-2004+ 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  *  TLP (22-Feb-2004) Ver 1.21                                              *
45  *   - Overflow for ADDH only affects upper 16bits (was modifying 32 bits)  *
46  *   - Internal Data Memory map is assigned here now                        *
47  *   - Cycle counts for invalid opcodes 7F1E and 7F1F are now 0             *
48  *                                                                          *
49  \**************************************************************************/
50 
51 
52 
53 #include "burnint.h"
54 #include "driver.h"
55 #include "state.h"
56 #include "tms32010.h"
57 
58 
59 #ifndef INLINE
60 #define INLINE static inline
61 #endif
62 
63 static INT32 addr_mask;
64 
65 UINT16 *tms32010_ram = NULL;
66 UINT16 *tms32010_rom = NULL;
67 
68 static void (*tms32010_write_port)(INT32,UINT16);
69 static UINT16 (*tms32010_read_port)(INT32);
70 
program_read_word_16be(UINT16 address)71 static UINT16 program_read_word_16be(UINT16 address)
72 {
73 	UINT16 r = tms32010_rom[address & addr_mask];
74 	r = (r << 8) | (r >> 8);
75 	return r;
76 }
77 
program_write_word_16be(UINT16 address,UINT16 data)78 static void program_write_word_16be(UINT16 address, UINT16 data)
79 {
80 	data = (data << 8) | (data >> 8);
81 
82 	tms32010_rom[address & addr_mask] = data;
83 }
84 
data_read_word_16be(UINT16 address)85 static UINT16 data_read_word_16be(UINT16 address)
86 {
87 	UINT16 r = BURN_ENDIAN_SWAP_INT16(tms32010_ram[address & 0xff]);
88 
89 	r = (r << 8) | (r >> 8);
90 
91 	return r;
92 }
93 
data_write_word_16be(UINT16 address,UINT16 data)94 static void data_write_word_16be(UINT16 address, UINT16 data)
95 {
96 	data = (data << 8) | (data >> 8);
97 
98 	tms32010_ram[address & 0xff] = BURN_ENDIAN_SWAP_INT16(data);
99 }
100 
io_read_word(INT32 offset)101 UINT16 io_read_word(INT32 offset)
102 {
103 	if (tms32010_read_port) {
104 		UINT16 r = tms32010_read_port(offset);
105 		return r;
106 	}
107 
108 	return 0;
109 }
110 
io_write_word(INT32 offset,UINT16 data)111 void io_write_word(INT32 offset, UINT16 data)
112 {
113 	if (tms32010_write_port) {
114 		tms32010_write_port(offset, data);
115 		return;
116 	}
117 }
118 
tms32010_set_write_port_handler(void (* pointer)(INT32,UINT16))119 void tms32010_set_write_port_handler(void (*pointer)(INT32,UINT16))
120 {
121 	tms32010_write_port = pointer;
122 }
123 
tms32010_set_read_port_handler(UINT16 (* pointer)(INT32))124 void tms32010_set_read_port_handler(UINT16 (*pointer)(INT32))
125 {
126 	tms32010_read_port = pointer;
127 }
128 
129 
130 #define TMS32010_BIO_In (io_read_word(TMS32010_BIO))
131 #define TMS32010_In(Port) (io_read_word(Port))
132 #define TMS32010_Out(Port,Value) (io_write_word(Port,Value))
133 #define TMS32010_ROM_RDMEM(A) (program_read_word_16be((A)))
134 #define TMS32010_ROM_WRMEM(A,V) (program_write_word_16be((A),V))
135 #define TMS32010_RAM_RDMEM(A) (data_read_word_16be((A)))
136 #define TMS32010_RAM_WRMEM(A,V) (data_write_word_16be((A),V))
137 #define TMS32010_RDOP(A) (program_read_word_16be((A)))
138 #define TMS32010_RDOP_ARG(A) (program_read_word_16be((A)))
139 
140 
141 
142 #define M_RDROM(A)		TMS32010_ROM_RDMEM(A)
143 #define M_WRTROM(A,V)	TMS32010_ROM_WRMEM(A,V)
144 #define M_RDRAM(A)		TMS32010_RAM_RDMEM(A)
145 #define M_WRTRAM(A,V)	TMS32010_RAM_WRMEM(A,V)
146 #define M_RDOP(A)		TMS32010_RDOP(A)
147 #define M_RDOP_ARG(A)	TMS32010_RDOP_ARG(A)
148 #define P_IN(A)			TMS32010_In(A)
149 #define P_OUT(A,V)		TMS32010_Out(A,V)
150 #define BIO_IN			TMS32010_BIO_In
151 
152 
153 
154 typedef struct			/* Page 3-6 shows all registers */
155 {
156 	/******************** CPU Internal Registers *******************/
157 	UINT16	PC;
158 	UINT16	PREVPC;		/* previous program counter */
159 	UINT16	STR;
160 	PAIR	ACC;
161 	PAIR	ALU;
162 	PAIR	Preg;
163 	UINT16	Treg;
164 	UINT16	AR[2];
165 	UINT16	STACK[4];
166 
167 	/********************** Status data ****************************/
168 	PAIR	opcode;
169 	INT32	INTF;		/* Pending Interrupt flag */
170 	PAIR	oldacc;
171 	UINT16	memaccess;
172 
173 	UINT32  total_cycles;
174 	UINT32	cycles_start;
175 	INT32	icount;
176 	INT32   end_run;
177 } tms32010_Regs;
178 
179 static tms32010_Regs R;
180 
181 static int add_branch_cycle();
182 
183 /********  The following is the Status (Flag) register definition.  *********/
184 /* 15 | 14  |  13  | 12 | 11 | 10 | 9 |  8  | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0  */
185 /* OV | OVM | INTM |  1 |  1 |  1 | 1 | ARP | 1 | 1 | 1 | 1 | 1 | 1 | 1 | DP */
186 #define OV_FLAG		0x8000	/* OV   (Overflow flag) 1 indicates an overflow */
187 #define OVM_FLAG	0x4000	/* OVM  (Overflow Mode bit) 1 forces ACC overflow to greatest positive or negative saturation value */
188 #define INTM_FLAG	0x2000	/* INTM (Interrupt Mask flag) 0 enables maskable interrupts */
189 #define ARP_REG		0x0100	/* ARP  (Auxiliary Register Pointer) */
190 #define DP_REG		0x0001	/* DP   (Data memory Pointer (bank) bit) */
191 
192 #define OV		( R.STR & OV_FLAG)			/* OV   (Overflow flag) */
193 #define OVM		( R.STR & OVM_FLAG)			/* OVM  (Overflow Mode bit) 1 indicates an overflow */
194 #define INTM	( R.STR & INTM_FLAG)		/* INTM (Interrupt enable flag) 0 enables maskable interrupts */
195 #define ARP		((R.STR & ARP_REG) >> 8)	/* ARP  (Auxiliary Register Pointer) */
196 #define DP		((R.STR & DP_REG) << 7)		/* DP   (Data memory Pointer bit) */
197 
198 #define DMA_DP	(DP | (R.opcode.b.l & 0x7f))	/* address used in direct memory access operations */
199 #define DMA_DP1	(0x80 | R.opcode.b.l)			/* address used in direct memory access operations for sst instruction */
200 #define IND		(R.AR[ARP] & 0xff)				/* address used in indirect memory access operations */
201 
202 
203 
204 
205 /************************************************************************
206  *  Shortcuts
207  ************************************************************************/
208 
CLR(UINT16 flag)209 INLINE void CLR(UINT16 flag) { R.STR &= ~flag; R.STR |= 0x1efe; }
SET(UINT16 flag)210 INLINE void SET(UINT16 flag) { R.STR |=  flag; R.STR |= 0x1efe; }
211 
212 
CALCULATE_ADD_OVERFLOW(INT32 addval)213 INLINE void CALCULATE_ADD_OVERFLOW(INT32 addval)
214 {
215 	if ((INT32)(~(R.oldacc.d ^ addval) & (R.oldacc.d ^ R.ACC.d)) < 0) {
216 		SET(OV_FLAG);
217 		if (OVM)
218 			R.ACC.d = ((INT32)R.oldacc.d < 0) ? 0x80000000 : 0x7fffffff;
219 	}
220 }
CALCULATE_SUB_OVERFLOW(INT32 subval)221 INLINE void CALCULATE_SUB_OVERFLOW(INT32 subval)
222 {
223 	if ((INT32)((R.oldacc.d ^ subval) & (R.oldacc.d ^ R.ACC.d)) < 0) {
224 		SET(OV_FLAG);
225 		if (OVM)
226 			R.ACC.d = ((INT32)R.oldacc.d < 0) ? 0x80000000 : 0x7fffffff;
227 	}
228 }
229 
POP_STACK(void)230 INLINE UINT16 POP_STACK(void)
231 {
232 	UINT16 data = R.STACK[3];
233 	R.STACK[3] = R.STACK[2];
234 	R.STACK[2] = R.STACK[1];
235 	R.STACK[1] = R.STACK[0];
236 	return (data & addr_mask);
237 }
PUSH_STACK(UINT16 data)238 INLINE void PUSH_STACK(UINT16 data)
239 {
240 	R.STACK[0] = R.STACK[1];
241 	R.STACK[1] = R.STACK[2];
242 	R.STACK[2] = R.STACK[3];
243 	R.STACK[3] = (data & addr_mask);
244 }
245 
UPDATE_AR(void)246 INLINE void UPDATE_AR(void)
247 {
248 	if (R.opcode.b.l & 0x30) {
249 		UINT16 tmpAR = R.AR[ARP];
250 		if (R.opcode.b.l & 0x20) tmpAR++ ;
251 		if (R.opcode.b.l & 0x10) tmpAR-- ;
252 		R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
253 	}
254 }
UPDATE_ARP(void)255 INLINE void UPDATE_ARP(void)
256 {
257 	if (~R.opcode.b.l & 0x08) {
258 		if (R.opcode.b.l & 0x01) SET(ARP_REG);
259 		else CLR(ARP_REG);
260 	}
261 }
262 
263 
getdata(UINT8 shift,UINT8 signext)264 INLINE void getdata(UINT8 shift,UINT8 signext)
265 {
266 	if (R.opcode.b.l & 0x80)
267 		R.memaccess = IND;
268 	else
269 		R.memaccess = DMA_DP;
270 
271 	R.ALU.d = (UINT16)M_RDRAM(R.memaccess);
272 	if (signext) R.ALU.d = (INT16)R.ALU.d;
273 	R.ALU.d <<= shift;
274 	if (R.opcode.b.l & 0x80) {
275 		UPDATE_AR();
276 		UPDATE_ARP();
277 	}
278 }
279 
putdata(UINT16 data)280 INLINE void putdata(UINT16 data)
281 {
282 	if (R.opcode.b.l & 0x80)
283 		R.memaccess = IND;
284 	else
285 		R.memaccess = DMA_DP;
286 
287 	if (R.opcode.b.l & 0x80) {
288 		UPDATE_AR();
289 		UPDATE_ARP();
290 	}
291 	M_WRTRAM(R.memaccess,data);
292 }
putdata_sar(UINT8 data)293 INLINE void putdata_sar(UINT8 data)
294 {
295 	if (R.opcode.b.l & 0x80)
296 		R.memaccess = IND;
297 	else
298 		R.memaccess = DMA_DP;
299 
300 	if (R.opcode.b.l & 0x80) {
301 		UPDATE_AR();
302 		UPDATE_ARP();
303 	}
304 	M_WRTRAM(R.memaccess,R.AR[data]);
305 }
putdata_sst(UINT16 data)306 INLINE void putdata_sst(UINT16 data)
307 {
308 	if (R.opcode.b.l & 0x80)
309 		R.memaccess = IND;
310 	else
311 		R.memaccess = DMA_DP1;  /* Page 1 only */
312 
313 	if (R.opcode.b.l & 0x80) {
314 		UPDATE_AR();
315 	}
316 	M_WRTRAM(R.memaccess,data);
317 }
318 
319 
320 
321 /************************************************************************
322  *  Emulate the Instructions
323  ************************************************************************/
324 
325 /* This following function is here to fill in the void for */
326 /* the opcode call function. This function is never called. */
327 
opcodes_7F(void)328 static void opcodes_7F(void)  { }
329 
330 
illegal(void)331 static void illegal(void)
332 {
333 		logerror("TMS32010:  PC=%04x,  Illegal opcode = %04x\n", (R.PC-1), R.opcode.w.l);
334 }
335 
abst(void)336 static void abst(void)
337 {
338 		if ( (INT32)(R.ACC.d) < 0 ) {
339 			R.ACC.d = -R.ACC.d;
340 			if (OVM && (R.ACC.d == 0x80000000)) R.ACC.d-- ;
341 		}
342 }
343 
344 /*** The manual does not mention overflow with the ADD? instructions *****
345  *** however I implemented overflow, coz it doesnt make sense otherwise **
346  *** and newer generations of this type of chip supported it. I think ****
347  *** the manual is wrong (apart from other errors the manual has). *******
348 
349 static void add_sh(void)    { getdata(R.opcode.b.h,1); R.ACC.d += R.ALU.d; }
350 static void addh(void)      { getdata(0,0); R.ACC.d += (R.ALU.d << 16); }
351  ***/
352 
add_sh(void)353 static void add_sh(void)
354 {
355 	R.oldacc.d = R.ACC.d;
356 	getdata((R.opcode.b.h & 0xf),1);
357 	R.ACC.d += R.ALU.d;
358 	CALCULATE_ADD_OVERFLOW(R.ALU.d);
359 }
addh(void)360 static void addh(void)
361 {
362 	R.oldacc.d = R.ACC.d;
363 	getdata(0,0);
364 	R.ACC.w.h += R.ALU.w.l;
365 	if ((INT16)(~(R.oldacc.w.h ^ R.ALU.w.h) & (R.oldacc.w.h ^ R.ACC.w.h)) < 0) {
366 		SET(OV_FLAG);
367 		if (OVM)
368 			R.ACC.w.h = ((INT16)R.oldacc.w.h < 0) ? 0x8000 : 0x7fff;
369 	}
370 }
adds(void)371 static void adds(void)
372 {
373 	R.oldacc.d = R.ACC.d;
374 	getdata(0,0);
375 	R.ACC.d += R.ALU.d;
376 	CALCULATE_ADD_OVERFLOW(R.ALU.d);
377 }
and_(void)378 static void and_(void)
379 {
380 	getdata(0,0);
381 	R.ACC.d &= R.ALU.d;
382 }
apac(void)383 static void apac(void)
384 {
385 	R.oldacc.d = R.ACC.d;
386 	R.ACC.d += R.Preg.d;
387 	CALCULATE_ADD_OVERFLOW(R.Preg.d);
388 }
br(void)389 static void br(void)
390 {
391 	R.PC = M_RDOP_ARG(R.PC);
392 }
banz(void)393 static void banz(void)
394 {
395 	if (R.AR[ARP] & 0x01ff) {
396 		R.PC = M_RDOP_ARG(R.PC);
397 		R.icount -= add_branch_cycle();
398 	}
399 	else
400 		R.PC++ ;
401 	R.ALU.w.l = R.AR[ARP];
402 	R.ALU.w.l-- ;
403 	R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (R.ALU.w.l & 0x01ff);
404 }
bgez(void)405 static void bgez(void)
406 {
407 	if ( (INT32)(R.ACC.d) >= 0 ) {
408 		R.PC = M_RDOP_ARG(R.PC);
409 		R.icount -= add_branch_cycle();
410 	}
411 	else
412 		R.PC++ ;
413 }
bgz(void)414 static void bgz(void)
415 {
416 	if ( (INT32)(R.ACC.d) > 0 ) {
417 		R.PC = M_RDOP_ARG(R.PC);
418 		R.icount -= add_branch_cycle();
419 	}
420 	else
421 		R.PC++ ;
422 }
bioz(void)423 static void bioz(void)
424 {
425 	if (BIO_IN != CPU_IRQSTATUS_NONE) {
426 		R.PC = M_RDOP_ARG(R.PC);
427 		R.icount -= add_branch_cycle();
428 	}
429 	else
430 		R.PC++ ;
431 }
blez(void)432 static void blez(void)
433 {
434 	if ( (INT32)(R.ACC.d) <= 0 ) {
435 		R.PC = M_RDOP_ARG(R.PC);
436 		R.icount -= add_branch_cycle();
437 	}
438 	else
439 		R.PC++ ;
440 }
blz(void)441 static void blz(void)
442 {
443 	if ( (INT32)(R.ACC.d) <  0 ) {
444 		R.PC = M_RDOP_ARG(R.PC);
445 		R.icount -= add_branch_cycle();
446 	}
447 	else
448 		R.PC++ ;
449 }
bnz(void)450 static void bnz(void)
451 {
452 	if (R.ACC.d != 0) {
453 		R.PC = M_RDOP_ARG(R.PC);
454 		R.icount -= add_branch_cycle();
455 	}
456 	else
457 		R.PC++ ;
458 }
bv(void)459 static void bv(void)
460 {
461 	if (OV) {
462 		CLR(OV_FLAG);
463 		R.PC = M_RDOP_ARG(R.PC);
464 		R.icount -= add_branch_cycle();
465 	}
466 	else
467 		R.PC++ ;
468 }
bz(void)469 static void bz(void)
470 {
471 	if (R.ACC.d == 0) {
472 		R.PC = M_RDOP_ARG(R.PC);
473 		R.icount -= add_branch_cycle();
474 	}
475 	else
476 		R.PC++ ;
477 }
cala(void)478 static void cala(void)
479 {
480 	PUSH_STACK(R.PC);
481 	R.PC = R.ACC.w.l & addr_mask;
482 }
call(void)483 static void call(void)
484 {
485 	R.PC++ ;
486 	PUSH_STACK(R.PC);
487 	R.PC = M_RDOP_ARG((R.PC - 1));// & addr_mask;
488 }
dint(void)489 static void dint(void)
490 {
491 	SET(INTM_FLAG);
492 }
dmov(void)493 static void dmov(void)
494 {
495 	getdata(0,0);
496 	M_WRTRAM((R.memaccess + 1),R.ALU.w.l);
497 }
eint(void)498 static void eint(void)
499 {
500 	CLR(INTM_FLAG);
501 }
in_p(void)502 static void in_p(void)
503 {
504 	R.ALU.w.l = P_IN( (R.opcode.b.h & 7) );
505 	putdata(R.ALU.w.l);
506 }
lac_sh(void)507 static void lac_sh(void)
508 {
509 	getdata((R.opcode.b.h & 0x0f),1);
510 	R.ACC.d = R.ALU.d;
511 }
lack(void)512 static void lack(void)
513 {
514 	R.ACC.d = R.opcode.b.l;
515 }
lar_ar0(void)516 static void lar_ar0(void)
517 {
518 	getdata(0,0);
519 	R.AR[0] = R.ALU.w.l;
520 }
lar_ar1(void)521 static void lar_ar1(void)
522 {
523 	getdata(0,0);
524 	R.AR[1] = R.ALU.w.l;
525 }
lark_ar0(void)526 static void lark_ar0(void)
527 {
528 	R.AR[0] = R.opcode.b.l;
529 }
lark_ar1(void)530 static void lark_ar1(void)
531 {
532 	R.AR[1] = R.opcode.b.l;
533 }
larp_mar(void)534 static void larp_mar(void)
535 {
536 	if (R.opcode.b.l & 0x80) {
537 		UPDATE_AR();
538 		UPDATE_ARP();
539 	}
540 }
ldp(void)541 static void ldp(void)
542 {
543 	getdata(0,0);
544 	if (R.ALU.d & 1)
545 		SET(DP_REG);
546 	else
547 		CLR(DP_REG);
548 }
ldpk(void)549 static void ldpk(void)
550 {
551 	if (R.opcode.b.l & 1)
552 		SET(DP_REG);
553 	else
554 		CLR(DP_REG);
555 }
lst(void)556 static void lst(void)
557 {
558 	if (R.opcode.b.l & 0x80) {
559 		R.opcode.b.l |= 0x08; /* In Indirect Addressing mode, next ARP is not supported here so mask it */
560 	}
561 	getdata(0,0);
562 	R.ALU.w.l &= (~INTM_FLAG);	/* Must not affect INTM */
563 	R.STR &= INTM_FLAG;
564 	R.STR |= R.ALU.w.l;
565 	R.STR |= 0x1efe;
566 }
lt(void)567 static void lt(void)
568 {
569 	getdata(0,0);
570 	R.Treg = R.ALU.w.l;
571 }
lta(void)572 static void lta(void)
573 {
574 	R.oldacc.d = R.ACC.d;
575 	getdata(0,0);
576 	R.Treg = R.ALU.w.l;
577 	R.ACC.d += R.Preg.d;
578 	CALCULATE_ADD_OVERFLOW(R.Preg.d);
579 }
ltd(void)580 static void ltd(void)
581 {
582 	R.oldacc.d = R.ACC.d;
583 	getdata(0,0);
584 	R.Treg = R.ALU.w.l;
585 	M_WRTRAM((R.memaccess + 1),R.ALU.w.l);
586 	R.ACC.d += R.Preg.d;
587 	CALCULATE_ADD_OVERFLOW(R.Preg.d);
588 }
mpy(void)589 static void mpy(void)
590 {
591 	getdata(0,0);
592 	R.Preg.d = (INT16)R.ALU.w.l * (INT16)R.Treg;
593 	if (R.Preg.d == 0x40000000) R.Preg.d = 0xc0000000;
594 }
mpyk(void)595 static void mpyk(void)
596 {
597 	R.Preg.d = (INT16)R.Treg * ((INT16)(R.opcode.w.l << 3) >> 3);
598 }
nop(void)599 static void nop(void)
600 {
601 	/* Nothing to do */
602 }
or_(void)603 static void or_(void)
604 {
605 	getdata(0,0);
606 	R.ACC.w.l |= R.ALU.w.l;
607 }
out_p(void)608 static void out_p(void)
609 {
610 	getdata(0,0);
611 	P_OUT( (R.opcode.b.h & 7), R.ALU.w.l );
612 }
pac(void)613 static void pac(void)
614 {
615 	R.ACC.d = R.Preg.d;
616 }
pop(void)617 static void pop(void)
618 {
619 	R.ACC.w.l = POP_STACK();
620 	R.ACC.w.h = 0x0000;
621 }
push(void)622 static void push(void)
623 {
624 	PUSH_STACK(R.ACC.w.l);
625 }
ret(void)626 static void ret(void)
627 {
628 	R.PC = POP_STACK();
629 }
rovm(void)630 static void rovm(void)
631 {
632 	CLR(OVM_FLAG);
633 }
sach_sh(void)634 static void sach_sh(void)
635 {
636 	R.ALU.d = (R.ACC.d << (R.opcode.b.h & 7));
637 	putdata(R.ALU.w.h);
638 }
sacl(void)639 static void sacl(void)
640 {
641 	putdata(R.ACC.w.l);
642 }
sar_ar0(void)643 static void sar_ar0(void)
644 {
645 	putdata_sar(0);
646 }
sar_ar1(void)647 static void sar_ar1(void)
648 {
649 	putdata_sar(1);
650 }
sovm(void)651 static void sovm(void)
652 {
653 	SET(OVM_FLAG);
654 }
spac(void)655 static void spac(void)
656 {
657 	R.oldacc.d = R.ACC.d;
658 	R.ACC.d -= R.Preg.d;
659 	CALCULATE_SUB_OVERFLOW(R.Preg.d);
660 }
sst(void)661 static void sst(void)
662 {
663 	putdata_sst(R.STR);
664 }
sub_sh(void)665 static void sub_sh(void)
666 {
667 	R.oldacc.d = R.ACC.d;
668 	getdata((R.opcode.b.h & 0x0f),1);
669 	R.ACC.d -= R.ALU.d;
670 	CALCULATE_SUB_OVERFLOW(R.ALU.d);
671 }
subc(void)672 static void subc(void)
673 {
674 	R.oldacc.d = R.ACC.d;
675 	getdata(15,0);
676 	R.ALU.d = (INT32) R.ACC.d - R.ALU.d;
677 	if ((INT32)((R.oldacc.d ^ R.ALU.d) & (R.oldacc.d ^ R.ACC.d)) < 0)
678 		SET(OV_FLAG);
679 	if ( (INT32)(R.ALU.d) >= 0 )
680 		R.ACC.d = ((R.ALU.d << 1) + 1);
681 	else
682 		R.ACC.d = (R.ACC.d << 1);
683 }
subh(void)684 static void subh(void)
685 {
686 	R.oldacc.d = R.ACC.d;
687 	getdata(16,0);
688 	R.ACC.d -= R.ALU.d;
689 	CALCULATE_SUB_OVERFLOW(R.ALU.d);
690 }
subs(void)691 static void subs(void)
692 {
693 	R.oldacc.d = R.ACC.d;
694 	getdata(0,0);
695 	R.ACC.d -= R.ALU.d;
696 	CALCULATE_SUB_OVERFLOW(R.ALU.d);
697 }
tblr(void)698 static void tblr(void)
699 {
700 	R.ALU.d = M_RDROM((R.ACC.w.l & addr_mask));
701 	putdata(R.ALU.w.l);
702 	R.STACK[0] = R.STACK[1];
703 }
tblw(void)704 static void tblw(void)
705 {
706 	getdata(0,0);
707 	M_WRTROM(((R.ACC.w.l & addr_mask)),R.ALU.w.l);
708 	R.STACK[0] = R.STACK[1];
709 }
xor_(void)710 static void xor_(void)
711 {
712 	getdata(0,0);
713 	R.ACC.w.l ^= R.ALU.w.l;
714 }
zac(void)715 static void zac(void)
716 {
717 	R.ACC.d = 0;
718 }
zalh(void)719 static void zalh(void)
720 {
721 	getdata(0,0);
722 	R.ACC.w.h = R.ALU.w.l;
723 	R.ACC.w.l = 0x0000;
724 }
zals(void)725 static void zals(void)
726 {
727 	getdata(0,0);
728 	R.ACC.w.l = R.ALU.w.l;
729 	R.ACC.w.h = 0x0000;
730 }
731 
732 
733 /***********************************************************************
734  *  Cycle Timings
735  ***********************************************************************/
736 
737 typedef void ( *opcode_func ) ();
738 
739 struct tms32010_opcode
740 {
741 	UINT8       cycles;
742 	opcode_func function;
743 };
744 
745 const tms32010_opcode s_opcode_main[256]=
746 {
747 /*00*/  {1, &add_sh  },{1, &add_sh    },{1, &add_sh    },{1, &add_sh    },{1, &add_sh    },{1, &add_sh    },{1, &add_sh    },{1, &add_sh    },
748 /*08*/  {1, &add_sh  },{1, &add_sh    },{1, &add_sh    },{1, &add_sh    },{1, &add_sh    },{1, &add_sh    },{1, &add_sh    },{1, &add_sh    },
749 /*10*/  {1, &sub_sh  },{1, &sub_sh    },{1, &sub_sh    },{1, &sub_sh    },{1, &sub_sh    },{1, &sub_sh    },{1, &sub_sh    },{1, &sub_sh    },
750 /*18*/  {1, &sub_sh  },{1, &sub_sh    },{1, &sub_sh    },{1, &sub_sh    },{1, &sub_sh    },{1, &sub_sh    },{1, &sub_sh    },{1, &sub_sh    },
751 /*20*/  {1, &lac_sh  },{1, &lac_sh    },{1, &lac_sh    },{1, &lac_sh    },{1, &lac_sh    },{1, &lac_sh    },{1, &lac_sh    },{1, &lac_sh    },
752 /*28*/  {1, &lac_sh  },{1, &lac_sh    },{1, &lac_sh    },{1, &lac_sh    },{1, &lac_sh    },{1, &lac_sh    },{1, &lac_sh    },{1, &lac_sh    },
753 /*30*/  {1, &sar_ar0 },{1, &sar_ar1   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
754 /*38*/  {1, &lar_ar0 },{1, &lar_ar1   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
755 /*40*/  {2, &in_p    },{2, &in_p      },{2, &in_p      },{2, &in_p      },{2, &in_p      },{2, &in_p      },{2, &in_p      },{2, &in_p      },
756 /*48*/  {2, &out_p   },{2, &out_p     },{2, &out_p     },{2, &out_p     },{2, &out_p     },{2, &out_p     },{2, &out_p     },{2, &out_p     },
757 /*50*/  {1, &sacl    },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
758 /*58*/  {1, &sach_sh },{1, &sach_sh   },{1, &sach_sh   },{1, &sach_sh   },{1, &sach_sh   },{1, &sach_sh   },{1, &sach_sh   },{1, &sach_sh   },
759 /*60*/  {1, &addh    },{1, &adds      },{1, &subh      },{1, &subs      },{1, &subc      },{1, &zalh      },{1, &zals      },{3, &tblr      },
760 /*68*/  {1, &larp_mar},{1, &dmov      },{1, &lt        },{1, &ltd       },{1, &lta       },{1, &mpy       },{1, &ldpk      },{1, &ldp       },
761 /*70*/  {1, &lark_ar0},{1, &lark_ar1  },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
762 /*78*/  {1, &xor_    },{1, &and_      },{1, &or_       },{1, &lst       },{1, &sst       },{3, &tblw      },{1, &lack      },{0, &opcodes_7F    },
763 /*80*/  {1, &mpyk    },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },
764 /*88*/  {1, &mpyk    },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },
765 /*90*/  {1, &mpyk    },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },
766 /*98*/  {1, &mpyk    },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },{1, &mpyk      },
767 /*A0*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
768 /*A8*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
769 /*B0*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
770 /*B8*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
771 /*C0*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
772 /*C8*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
773 /*D0*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
774 /*D8*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
775 /*E0*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
776 /*E8*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
777 /*F0*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{1, &banz      },{1, &bv        },{1, &bioz      },{0, &illegal   },
778 /*F8*/  {2, &call    },{2, &br        },{1, &blz       },{1, &blez      },{1, &bgz       },{1, &bgez      },{1, &bnz       },{1, &bz        }
779 };
780 
781 const tms32010_opcode s_opcode_7F[32]=
782 {
783 /*80*/  {1, &nop     },{1, &dint      },{1, &eint      },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
784 /*88*/  {1, &abst    },{1, &zac       },{1, &rovm      },{1, &sovm      },{2, &cala      },{2, &ret       },{1, &pac       },{1, &apac      },
785 /*90*/  {1, &spac    },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },{0, &illegal   },
786 /*98*/  {0, &illegal },{0, &illegal   },{0, &illegal   },{0, &illegal   },{2, &push      },{2, &pop       },{0, &illegal   },{0, &illegal   }
787 };
788 
add_branch_cycle()789 static int add_branch_cycle()
790 {
791 	return s_opcode_main[R.opcode.b.h].cycles;
792 }
793 
794 
795 /****************************************************************************
796  *  Inits CPU emulation
797  ****************************************************************************/
tms32010_init(void)798 void tms32010_init (void)
799 {
800 #if 0
801 	state_save_register_item("tms32010", index, R.PC);
802 	state_save_register_item("tms32010", index, R.PREVPC);
803 	state_save_register_item("tms32010", index, R.STR);
804 	state_save_register_item("tms32010", index, R.ACC.d);
805 	state_save_register_item("tms32010", index, R.ALU.d);
806 	state_save_register_item("tms32010", index, R.Preg.d);
807 	state_save_register_item("tms32010", index, R.Treg);
808 	state_save_register_item("tms32010", index, R.AR[0]);
809 	state_save_register_item("tms32010", index, R.AR[1]);
810 	state_save_register_item("tms32010", index, R.STACK[0]);
811 	state_save_register_item("tms32010", index, R.STACK[1]);
812 	state_save_register_item("tms32010", index, R.STACK[2]);
813 	state_save_register_item("tms32010", index, R.STACK[3]);
814 	state_save_register_item("tms32010", index, R.INTF);
815 	state_save_register_item("tms32010", index, R.opcode.d);
816 #endif
817 }
818 
819 /****************************************************************************
820  *  Reset registers to their initial values
821  ****************************************************************************/
tms32010_reset(void)822 void tms32010_reset (void)
823 {
824 	memset(&R, 0, sizeof(R));
825 	R.PC    = 0;
826 	R.STR   = 0;
827 	R.ACC.d = 0;
828 	R.INTF  = TMS32010_INT_NONE;
829 	addr_mask = 0x0fff;	/* TMS32010 can only address 0x0fff */
830 						/* however other TMS3201x devices   */
831 						/* can address up to 0xffff (incase */
832 						/* their support is ever added).    */
833 
834 	/* Setup Status Register : 7efe */
835 	CLR((OV_FLAG | ARP_REG | DP_REG));
836 	SET((OVM_FLAG | INTM_FLAG));
837 
838 	R.total_cycles = 0;
839 }
840 
841 
842 /****************************************************************************
843  *  Shut down CPU emulation
844  ****************************************************************************/
tms32010_exit(void)845 void tms32010_exit (void)
846 {
847 	/* nothing to do ? */
848 }
849 
850 
851 /****************************************************************************
852  *  Issue an interrupt if necessary
853  ****************************************************************************/
tms32010_Ext_IRQ(void)854 int tms32010_Ext_IRQ(void)
855 {
856 	if (INTM == 0)
857 	{
858 		logerror("TMS32010:  EXT INTERRUPT\n");
859 		R.INTF = TMS32010_INT_NONE;
860 		SET(INTM_FLAG);
861 		PUSH_STACK(R.PC);
862 		R.PC = 0x0002;
863 		return (s_opcode_7F[0x1c].cycles + s_opcode_7F[0x01].cycles);   /* 3 cycles used due to PUSH and DINT operation ? */
864 	}
865 	return (0);
866 }
867 
868 /****************************************************************************
869  *  Execute IPeriod. Return 0 if emulation should be stopped
870  ****************************************************************************/
tms32010Run(int cycles)871 int tms32010Run(int cycles)
872 {
873 	R.icount = cycles;
874 	R.cycles_start = cycles;
875 
876 	R.end_run = 0;
877 
878 	do
879 	{
880 		if (R.INTF) {
881 			/* Dont service INT if prev instruction was MPY, MPYK or EINT */
882 			if ((R.opcode.b.h != 0x6d) && ((R.opcode.b.h & 0xe0) != 0x80) && (R.opcode.w.l != 0x7f82))
883 				R.icount -= tms32010_Ext_IRQ();
884 		}
885 
886 		R.PREVPC = R.PC;
887 
888 		//CALL_MAME_DEBUG;
889 
890 		R.opcode.d = M_RDOP(R.PC);
891 		R.PC++;
892 
893 		if (R.opcode.b.h != 0x7f)	{ /* Do all opcodes except the 7Fxx ones */
894 			R.icount -= s_opcode_main[R.opcode.b.h].cycles;
895 			(*s_opcode_main[R.opcode.b.h].function)();
896 		}
897 		else { /* Opcode major byte 7Fxx has many opcodes in its minor byte */
898 			R.icount -= s_opcode_7F[(R.opcode.b.l & 0x1f)].cycles;
899 			(*s_opcode_7F[(R.opcode.b.l & 0x1f)].function)();
900 		}
901 	} while (R.icount > 0 && !R.end_run);
902 
903 	cycles = cycles - R.icount;
904 	R.total_cycles += cycles;
905 
906 	R.cycles_start = 0;
907 	R.icount = 0;
908 
909 	return cycles;
910 }
911 
tms32010TotalCycles()912 UINT32 tms32010TotalCycles()
913 {
914 	return R.total_cycles + (R.cycles_start - R.icount);
915 }
916 
tms32010NewFrame()917 void tms32010NewFrame()
918 {
919 	R.total_cycles = 0;
920 }
921 
tms32010RunEnd()922 void tms32010RunEnd()
923 {
924 	R.end_run = 1;
925 }
926 
tms32010_scan(INT32 nAction)927 void tms32010_scan(INT32 nAction)
928 {
929 	if (nAction & ACB_DRIVER_DATA) {
930 		struct BurnArea ba;
931 		memset(&ba, 0, sizeof(ba));
932 		ba.Data	  = &R;
933 		ba.nLen	  = sizeof(tms32010_Regs);
934 		ba.szName = "tms32010 Regs";
935 		BurnAcb(&ba);
936 	}
937 }
938 
tms32010_get_pc()939 UINT16 tms32010_get_pc()
940 {
941 	return R.PC;
942 }
943 
944 /****************************************************************************
945  *  Set IRQ line state
946  ****************************************************************************/
tms32010_set_irq_line(int irqline,int state)947 void tms32010_set_irq_line(int irqline, int state)
948 {
949 	/* Pending Interrupts cannot be cleared! */
950 	if (state == CPU_IRQSTATUS_ACK) R.INTF |=  TMS32010_INT_PENDING;
951 }
952 
953