1 /****************************************************************************
2  *					Texas Instruments TMS320C10 DSP Emulator				*
3  *																			*
4  *						Copyright (C) 1999 by Quench						*
5  *		You are not allowed to distribute this software commercially.		*
6  *						Written for the MAME project.						*
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.						*
12  *																			*
13  **************************************************************************/
14 
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include "driver.h"
20 #include "cpuintrf.h"
21 #include "tms32010.h"
22 
23 #include <retro_inline.h>
24 
25 #define M_RDROM(A)		TMS320C10_ROM_RDMEM(A)
26 #define M_WRTROM(A,V)	TMS320C10_ROM_WRMEM(A,V)
27 #define M_RDRAM(A)		TMS320C10_RAM_RDMEM(A)
28 #define M_WRTRAM(A,V)	TMS320C10_RAM_WRMEM(A,V)
29 #define M_RDOP(A)		TMS320C10_RDOP(A)
30 #define M_RDOP_ARG(A)	TMS320C10_RDOP_ARG(A)
31 #define M_IN(A)			TMS320C10_In(A)
32 #define M_OUT(A,V)		TMS320C10_Out(A,V)
33 
34 #define ADDR_MASK		TMS320C10_ADDR_MASK
35 
36 typedef struct
37 {
38 	UINT16	PREPC;		/* previous program counter */
39 	UINT16  PC;
40 	INT32   ACC, Preg;
41 	INT32   ALU;
42 	UINT16  Treg;
43 	UINT16  AR[2], STACK[4], STR;
44 	int     pending_irq, BIO_pending_irq;
45 	int     irq_state;
46 	int     (*irq_callback)(int irqline);
47 } tms320c10_Regs;
48 
49 
50 /********  The following is the Status (Flag) register definition.  *********/
51 /* 15 | 14  |  13  | 12 | 11 | 10 | 9 |  8  | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0  */
52 /* OV | OVM | INTM |  1 |  1 |  1 | 1 | ARP | 1 | 1 | 1 | 1 | 1 | 1 | 1 | DP */
53 #define OV_FLAG		0x8000	/* OV	(Overflow flag) 1 indicates an overflow */
54 #define OVM_FLAG	0x4000	/* OVM	(Overflow Mode bit) 1 forces ACC overflow to greatest positive or negative saturation value */
55 #define INTM_FLAG	0x2000	/* INTM	(Interrupt Mask flag) 0 enables maskable interrupts */
56 #define ARP_REG		0x0100	/* ARP	(Auxiliary Register Pointer) */
57 #define DP_REG		0x0001	/* DP	(Data memory Pointer (bank) bit) */
58 
59 static UINT16   opcode=0;
60 static UINT8	opcode_major=0, opcode_minor, opcode_minr;	/* opcode split into MSB and LSB */
61 static tms320c10_Regs R;
62 int tms320c10_ICount;
63 static INT32 tmpacc;
64 typedef void (*opcode_fn) (void);
65 
66 
67 #define OV		 ( R.STR & OV_FLAG)			/* OV	(Overflow flag) */
68 #define OVM		 ( R.STR & OVM_FLAG)		/* OVM	(Overflow Mode bit) 1 indicates an overflow */
69 #define INTM	 ( R.STR & INTM_FLAG)		/* INTM	(Interrupt enable flag) 0 enables maskable interrupts */
70 #define ARP		 ((R.STR & ARP_REG) >> 8 )	/* ARP	(Auxiliary Register Pointer) */
71 #define DP		 ((R.STR & DP_REG) << 7)	/* DP	(Data memory Pointer bit) */
72 
73 #define dma		 (DP | (opcode_minor & 0x07f))	/* address used in direct memory access operations */
74 #define dmapage1 (0x80 | opcode_minor)			/* address used in direct memory access operations for sst instruction */
75 
76 #define ind		 (R.AR[ARP] & 0x00ff)			/* address used in indirect memory access operations */
77 UINT16			 memaccess;
78 #define memacc	 (memaccess = (opcode_minor & 0x80) ? ind : dma)
79 
80 
81 
CLR(UINT16 flag)82 static INLINE void CLR(UINT16 flag) { R.STR &= ~flag; R.STR |= 0x1efe; }
SET(UINT16 flag)83 static INLINE void SET(UINT16 flag) { R.STR |=  flag; R.STR |= 0x1efe; }
84 
getdata(UINT8 shift,UINT8 signext)85 static INLINE void getdata(UINT8 shift,UINT8 signext)
86 {
87 	if (opcode_minor & 0x80) memaccess = ind;
88 	else memaccess = dma;
89 	R.ALU = M_RDRAM(memaccess);
90 	if ((signext) && (R.ALU & 0x8000)) R.ALU |= 0xffff0000;
91 	else R.ALU &= 0x0000ffff;
92 	R.ALU <<= shift;
93 	if (opcode_minor & 0x80) {
94 		if ((opcode_minor & 0x20) || (opcode_minor & 0x10)) {
95 			UINT16 tmpAR = R.AR[ARP];
96 			if (opcode_minor & 0x20) tmpAR++ ;
97 			if (opcode_minor & 0x10) tmpAR-- ;
98 			R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
99 		}
100 		if (~opcode_minor & 0x08) {
101 			if (opcode_minor & 1) SET(ARP_REG);
102 			else CLR(ARP_REG);
103 		}
104 	}
105 }
getdata_lar(void)106 static INLINE void getdata_lar(void)
107 {
108 	if (opcode_minor & 0x80) memaccess = ind;
109 	else memaccess = dma;
110 	R.ALU = M_RDRAM(memaccess);
111 	if (opcode_minor & 0x80) {
112 		if ((opcode_minor & 0x20) || (opcode_minor & 0x10)) {
113 			if ((opcode_major & 1) != ARP) {
114 				UINT16 tmpAR = R.AR[ARP];
115 				if (opcode_minor & 0x20) tmpAR++ ;
116 				if (opcode_minor & 0x10) tmpAR-- ;
117 				R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
118 			}
119 		}
120 		if (~opcode_minor & 0x08) {
121 			if (opcode_minor & 1) SET(ARP_REG);
122 			else CLR(ARP_REG);
123 		}
124 	}
125 }
126 
putdata(UINT16 data)127 static INLINE void putdata(UINT16 data)
128 {
129 	if (opcode_minor & 0x80) memaccess = ind;
130 	else memaccess = dma;
131 	if (opcode_minor & 0x80) {
132 		if ((opcode_minor & 0x20) || (opcode_minor & 0x10)) {
133 			UINT16 tmpAR = R.AR[ARP];
134 			if (opcode_minor & 0x20) tmpAR++ ;
135 			if (opcode_minor & 0x10) tmpAR-- ;
136 			R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
137 		}
138 		if (~opcode_minor & 0x08) {
139 			if (opcode_minor & 1) SET(ARP_REG);
140 			else CLR(ARP_REG);
141 		}
142 	}
143 	if ((opcode_major == 0x30) || (opcode_major == 0x31)) {
144 		M_WRTRAM(memaccess,(R.AR[data])); }
145 	else M_WRTRAM(memaccess,(data&0xffff));
146 }
putdata_sst(UINT16 data)147 static INLINE void putdata_sst(UINT16 data)
148 {
149 	if (opcode_minor & 0x80) memaccess = ind;
150 	else memaccess = dmapage1;
151 	if (opcode_minor & 0x80) {
152 		if ((opcode_minor & 0x20) || (opcode_minor & 0x10)) {
153 			UINT16 tmpAR = R.AR[ARP];
154 			if (opcode_minor & 0x20) tmpAR++ ;
155 			if (opcode_minor & 0x10) tmpAR-- ;
156 			R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
157 		}
158 	}
159 	M_WRTRAM(memaccess,(data&0xffff));
160 }
161 
162 
M_ILLEGAL(void)163 void M_ILLEGAL(void)
164 {
165 	//logerror("TMS320C10:  PC = %04x,  Illegal opcode = %04x\n", (R.PC-1), opcode);
166 }
167 
168 
169 /* This following function is here to fill in the void for */
170 /* the opcode call function. This function is never called. */
other_7F_opcodes(void)171 static void other_7F_opcodes(void)  { }
172 
illegal(void)173 static void illegal(void)	{ M_ILLEGAL(); }
abst(void)174 static void abst(void)
175 		{
176 			if (R.ACC >= 0x80000000) {
177 				R.ACC = ~R.ACC;
178 				R.ACC++ ;
179 				if (OVM && (R.ACC == 0x80000000)) R.ACC-- ;
180 			}
181 		}
182 
183 /* ** The manual does not mention overflow with the ADD? instructions *****
184    ** however i implelemted overflow, coz it doesnt make sense otherwise **
185    ** and newer generations of this type of chip supported it. I think ****
186    ** the manual is wrong (apart from other errors the manual has). *******
187 
188 static void add_sh(void)	{ getdata(opcode_major,1); R.ACC += R.ALU; }
189 static void addh(void)		{ getdata(0,0); R.ACC += (R.ALU << 16); }
190 */
191 
add_sh(void)192 static void add_sh(void)
193 		{
194 			tmpacc = R.ACC;
195 			getdata(opcode_major,1);
196 			R.ACC += R.ALU;
197 			if (tmpacc > R.ACC) {
198 				SET(OV_FLAG);
199 				if (OVM) R.ACC = 0x7fffffff;
200 			}
201 			else CLR(OV_FLAG);
202 		}
addh(void)203 static void addh(void)
204 		{
205 			tmpacc = R.ACC;
206 			getdata(0,0);
207 			R.ACC += (R.ALU << 16);
208 			R.ACC &= 0xffff0000;
209 			R.ACC += (tmpacc & 0x0000ffff);
210 			if (tmpacc > R.ACC) {
211 				SET(OV_FLAG);
212 				if (OVM) {
213 					R.ACC &= 0x0000ffff; R.ACC |= 0x7fff0000;
214 				}
215 			}
216 			else CLR(OV_FLAG);
217 		}
adds(void)218 static void adds(void)
219 		{
220 			tmpacc = R.ACC;
221 			getdata(0,0);
222 			R.ACC += R.ALU;
223 			if (tmpacc > R.ACC) {
224 				SET(OV_FLAG);
225 				if (OVM) R.ACC = 0x7fffffff;
226 			}
227 			else CLR(OV_FLAG);
228 		}
_and(void)229 static void _and(void)
230 		{
231 			getdata(0,0);
232 			R.ACC &= R.ALU;
233 			R.ACC &= 0x0000ffff;
234 		}
apac(void)235 static void apac(void)
236 		{
237 			tmpacc = R.ACC;
238 			R.ACC += R.Preg;
239 			if (tmpacc > R.ACC) {
240 				SET(OV_FLAG);
241 				if (OVM) R.ACC = 0x7fffffff;
242 			}
243 			else CLR(OV_FLAG);
244 		}
br(void)245 static void br(void)		{ R.PC = M_RDOP_ARG(R.PC); }
banz(void)246 static void banz(void)
247 		{
248 			if ((R.AR[ARP] & 0x01ff) == 0) R.PC++ ;
249 			else R.PC = M_RDOP_ARG(R.PC);
250 			R.ALU = R.AR[ARP]; R.ALU-- ;
251 			R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (R.ALU & 0x01ff);
252 		}
bgez(void)253 static void bgez(void)
254 		{
255 			if (R.ACC >= 0) R.PC = M_RDOP_ARG(R.PC);
256 			else R.PC++ ;
257 		}
bgz(void)258 static void bgz(void)
259 		{
260 			if (R.ACC >  0) R.PC = M_RDOP_ARG(R.PC);
261 			else R.PC++ ;
262 		}
bioz(void)263 static void bioz(void)
264 		{
265 			if (R.BIO_pending_irq) R.PC = M_RDOP_ARG(R.PC);
266 			else R.PC++ ;
267 		}
blez(void)268 static void blez(void)
269 		{
270 			if (R.ACC <= 0) R.PC = M_RDOP_ARG(R.PC);
271 			else R.PC++ ;
272 		}
blz(void)273 static void blz(void)
274 		{
275 			if (R.ACC <  0) R.PC = M_RDOP_ARG(R.PC);
276 			else R.PC++ ;
277 		}
bnz(void)278 static void bnz(void)
279 		{
280 			if (R.ACC != 0) R.PC = M_RDOP_ARG(R.PC);
281 			else R.PC++ ;
282 		}
bv(void)283 static void bv(void)
284 		{
285 			if (OV) {
286 				R.PC = M_RDOP_ARG(R.PC);
287 				CLR(OV_FLAG);
288 			}
289 			else R.PC++ ;
290 		}
bz(void)291 static void bz(void)
292 		{
293 			if (R.ACC == 0) R.PC = M_RDOP_ARG(R.PC);
294 			else R.PC++ ;
295 		}
cala(void)296 static void cala(void)
297 		{
298 			R.STACK[0] = R.STACK[1];
299 			R.STACK[1] = R.STACK[2];
300 			R.STACK[2] = R.STACK[3];
301 			R.STACK[3] = R.PC & ADDR_MASK;
302 			R.PC = R.ACC & ADDR_MASK;
303 		}
call(void)304 static void call(void)
305 		{
306 			R.PC++ ;
307 			R.STACK[0] = R.STACK[1];
308 			R.STACK[1] = R.STACK[2];
309 			R.STACK[2] = R.STACK[3];
310 			R.STACK[3] = R.PC & ADDR_MASK;
311 			R.PC = M_RDOP_ARG((R.PC-1)) & ADDR_MASK;
312 		}
dint(void)313 static void dint(void)		{ SET(INTM_FLAG); }
dmov(void)314 static void dmov(void)		{ getdata(0,0); M_WRTRAM((memaccess+1),R.ALU); }
eint(void)315 static void eint(void)		{ CLR(INTM_FLAG); }
in_p(void)316 static void in_p(void)
317 		{
318 			R.ALU = M_IN((opcode_major & 7));
319 			putdata((R.ALU & 0x0000ffff));
320 		}
lac_sh(void)321 static void lac_sh(void)
322 		{
323 			getdata((opcode_major & 0x0f),1);
324 			R.ACC = R.ALU;
325 		}
lack(void)326 static void lack(void)		{ R.ACC = (opcode_minor & 0x000000ff); }
lar_ar0(void)327 static void lar_ar0(void)	{ getdata_lar(); R.AR[0] = R.ALU; }
lar_ar1(void)328 static void lar_ar1(void)	{ getdata_lar(); R.AR[1] = R.ALU; }
lark_ar0(void)329 static void lark_ar0(void)	{ R.AR[0] = (opcode_minor & 0x00ff); }
lark_ar1(void)330 static void lark_ar1(void)	{ R.AR[1] = (opcode_minor & 0x00ff); }
larp_mar(void)331 static void larp_mar(void)
332 		{
333 			if (opcode_minor & 0x80) {
334 				if ((opcode_minor & 0x20) || (opcode_minor & 0x10)) {
335 					UINT16 tmpAR = R.AR[ARP];
336 					if (opcode_minor & 0x20) tmpAR++ ;
337 					if (opcode_minor & 0x10) tmpAR-- ;
338 					R.AR[ARP] = (R.AR[ARP] & 0xfe00) | (tmpAR & 0x01ff);
339 				}
340 				if (~opcode_minor & 0x08) {
341 					if (opcode_minor & 0x01) SET(ARP_REG) ;
342 					else CLR(ARP_REG);
343 				}
344 			}
345 		}
ldp(void)346 static void ldp(void)
347 		{
348 			getdata(0,0);
349 			if (R.ALU & 1) SET(DP_REG);
350 			else CLR(DP_REG);
351 		}
ldpk(void)352 static void ldpk(void)
353 		{
354 			if (opcode_minor & 1) SET(DP_REG);
355 			else CLR(DP_REG);
356 		}
lst(void)357 static void lst(void)
358 		{
359 			tmpacc = R.STR;
360 			opcode_minor |= 0x08; /* This dont support next arp, so make sure it dont happen */
361 			getdata(0,0);
362 			R.STR = R.ALU;
363 			tmpacc &= INTM_FLAG;
364 			R.STR |= tmpacc;
365 			R.STR |= 0x1efe;
366 		}
lt(void)367 static void lt(void)		{ getdata(0,0); R.Treg = R.ALU; }
lta(void)368 static void lta(void)
369 		{
370 			tmpacc = R.ACC;
371 			getdata(0,0);
372 			R.Treg = R.ALU;
373 			R.ACC += R.Preg;
374 			if (tmpacc > R.ACC) {
375 				SET(OV_FLAG);
376 				if (OVM) R.ACC = 0x7fffffff;
377 			}
378 			else CLR(OV_FLAG);
379 		}
ltd(void)380 static void ltd(void)
381 		{
382 			tmpacc = R.ACC;
383 			getdata(0,0);
384 			R.Treg = R.ALU;
385 			R.ACC += R.Preg;
386 			if (tmpacc > R.ACC) {
387 				SET(OV_FLAG);
388 				if (OVM) R.ACC = 0x7fffffff;
389 			}
390 			else CLR(OV_FLAG);
391 			M_WRTRAM((memaccess+1),R.ALU);
392 		}
mpy(void)393 static void mpy(void)
394 		{
395 			getdata(0,0);
396 			if ((R.ALU == 0x00008000) && (R.Treg == 0x8000))
397 				R.Preg = 0xc0000000;
398 			else R.Preg = R.ALU * R.Treg;
399 		}
mpyk(void)400 static void mpyk(void)
401 		{
402 			if (opcode & 0x1000)
403 				R.Preg = R.Treg * ((opcode & 0x1fff) | 0xe000);
404 			else R.Preg = R.Treg * (opcode & 0x1fff);
405 		}
nop(void)406 static void nop(void)		{ }
_or(void)407 static void _or(void)
408 		{
409 			getdata(0,0);
410 			R.ALU &= 0x0000ffff;
411 			R.ACC |= R.ALU;
412 		}
out_p(void)413 static void out_p(void)
414 		{
415 			getdata(0,0);
416 			M_OUT((opcode_major & 7), (R.ALU & 0x0000ffff));
417 		}
pac(void)418 static void pac(void)		{ R.ACC = R.Preg; }
pop(void)419 static void pop(void)
420 		{
421 			R.ACC = R.STACK[3] & ADDR_MASK;
422 			R.STACK[3] = R.STACK[2];
423 			R.STACK[2] = R.STACK[1];
424 			R.STACK[1] = R.STACK[0];
425 		}
push(void)426 static void push(void)
427 		{
428 			R.STACK[0] = R.STACK[1];
429 			R.STACK[1] = R.STACK[2];
430 			R.STACK[2] = R.STACK[3];
431 			R.STACK[3] = R.ACC & ADDR_MASK;
432 		}
ret(void)433 static void ret(void)
434 		{
435 			R.PC = R.STACK[3] & ADDR_MASK;
436 			R.STACK[3] = R.STACK[2];
437 			R.STACK[2] = R.STACK[1];
438 			R.STACK[1] = R.STACK[0];
439 		}
rovm(void)440 static void rovm(void)		{ CLR(OVM_FLAG); }
sach_sh(void)441 static void sach_sh(void)	{ putdata(((R.ACC << (opcode_major & 7)) >> 16)); }
sacl(void)442 static void sacl(void)		{ putdata((R.ACC & 0x0000ffff)); }
sar_ar0(void)443 static void sar_ar0(void)	{ putdata(0); }
sar_ar1(void)444 static void sar_ar1(void)	{ putdata(1); }
sovm(void)445 static void sovm(void)		{ SET(OVM_FLAG); }
spac(void)446 static void spac(void)
447 		{
448 			INT32 tmpPreg = R.Preg;
449 			tmpacc = R.ACC ;
450 			/* if (tmpPreg & 0x8000) tmpPreg |= 0xffff0000; */
451 			R.ACC -= tmpPreg ;
452 			if (tmpacc < R.ACC) {
453 				SET(OV_FLAG);
454 				if (OVM) R.ACC = 0x80000000;
455 			}
456 			else CLR(OV_FLAG);
457 		}
sst(void)458 static void sst(void)		{ putdata_sst(R.STR); }
sub_sh(void)459 static void sub_sh(void)
460 		{
461 			tmpacc = R.ACC;
462 			getdata((opcode_major & 0x0f),1);
463 			R.ACC -= R.ALU;
464 			if (tmpacc < R.ACC) {
465 				SET(OV_FLAG);
466 				if (OVM) R.ACC = 0x80000000;
467 			}
468 			else CLR(OV_FLAG);
469 		}
subc(void)470 static void subc(void)
471 		{
472 			tmpacc = R.ACC;
473 			getdata(15,0);
474 			tmpacc -= R.ALU;
475 			if (tmpacc < 0) {
476 				R.ACC <<= 1;
477 				SET(OV_FLAG);
478 			}
479 			else R.ACC = ((tmpacc << 1) + 1);
480 		}
subh(void)481 static void subh(void)
482 		{
483 			tmpacc = R.ACC;
484 			getdata(0,0);
485 			R.ACC -= (R.ALU << 16);
486 			R.ACC &= 0xffff0000;
487 			R.ACC += (tmpacc & 0x0000ffff);
488 			if ((tmpacc & 0xffff0000) < (R.ACC & 0xffff0000)) {
489 				SET(OV_FLAG);
490 				if (OVM) {
491 					R.ACC = (tmpacc & 0x0000ffff);
492 					R.ACC |= 0x80000000 ;
493 				}
494 			}
495 			else CLR(OV_FLAG);
496 		}
subs(void)497 static void subs(void)
498 		{
499 			tmpacc = R.ACC;
500 			getdata(0,0);
501 			R.ACC -= R.ALU;
502 			if (tmpacc < R.ACC) {
503 				SET(OV_FLAG);
504 				if (OVM) R.ACC = 0x80000000;
505 			}
506 			else CLR(OV_FLAG);
507 		}
tblr(void)508 static void tblr(void)
509 		{
510 			R.ALU = M_RDROM((R.ACC & ADDR_MASK));
511 			putdata(R.ALU);
512 			R.STACK[0] = R.STACK[1];
513 		}
tblw(void)514 static void tblw(void)
515 		{
516 			getdata(0,0);
517 			M_WRTROM(((R.ACC & ADDR_MASK)),R.ALU);
518 			R.STACK[0] = R.STACK[1];
519 		}
_xor(void)520 static void _xor(void)
521 		{
522 			tmpacc = (R.ACC & 0xffff0000);
523 			getdata(0,0);
524 			R.ACC ^= R.ALU;
525 			R.ACC &= 0x0000ffff;
526 			R.ACC |= tmpacc;
527 		}
zac(void)528 static void zac(void)		{ R.ACC = 0; }
zalh(void)529 static void zalh(void)		{ getdata(16,0); R.ACC = R.ALU; }
zals(void)530 static void zals(void)		{ getdata(0 ,0); R.ACC = R.ALU; }
531 
532 
533 static unsigned cycles_main[256]=
534 {
535 /*00*/		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
536 /*10*/		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
537 /*20*/		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
538 /*30*/		1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0,
539 /*40*/		2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
540 /*50*/		1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
541 /*60*/		1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1,
542 /*70*/		1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 3, 1, 0,
543 /*80*/		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
544 /*90*/		1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
545 /*A0*/		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
546 /*B0*/		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
547 /*C0*/		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
548 /*D0*/		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
549 /*E0*/		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
550 /*F0*/		0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2
551 };
552 
553 static unsigned cycles_7F_other[32]=
554 {
555 /*80*/		1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 1, 1,
556 /*90*/		1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1,
557 };
558 
559 static opcode_fn opcode_main[256]=
560 {
561 /*00*/  add_sh		,add_sh		,add_sh		,add_sh		,add_sh		,add_sh		,add_sh		,add_sh
562 /*08*/ ,add_sh		,add_sh		,add_sh		,add_sh		,add_sh		,add_sh		,add_sh		,add_sh
563 /*10*/ ,sub_sh		,sub_sh		,sub_sh		,sub_sh		,sub_sh		,sub_sh		,sub_sh		,sub_sh
564 /*18*/ ,sub_sh		,sub_sh		,sub_sh		,sub_sh		,sub_sh		,sub_sh		,sub_sh		,sub_sh
565 /*20*/ ,lac_sh		,lac_sh		,lac_sh		,lac_sh		,lac_sh		,lac_sh		,lac_sh		,lac_sh
566 /*28*/ ,lac_sh		,lac_sh		,lac_sh		,lac_sh		,lac_sh		,lac_sh		,lac_sh		,lac_sh
567 /*30*/ ,sar_ar0		,sar_ar1	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
568 /*38*/ ,lar_ar0		,lar_ar1	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
569 /*40*/ ,in_p		,in_p		,in_p		,in_p		,in_p		,in_p		,in_p		,in_p
570 /*48*/ ,out_p		,out_p		,out_p		,out_p		,out_p		,out_p		,out_p		,out_p
571 /*50*/ ,sacl		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
572 /*58*/ ,sach_sh		,sach_sh	,sach_sh	,sach_sh	,sach_sh	,sach_sh	,sach_sh	,sach_sh
573 /*60*/ ,addh		,adds		,subh		,subs		,subc		,zalh		,zals		,tblr
574 /*68*/ ,larp_mar	,dmov		,lt			,ltd		,lta		,mpy		,ldpk		,ldp
575 /*70*/ ,lark_ar0	,lark_ar1	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
576 /*78*/ ,_xor			,_and		,_or			,lst		,sst		,tblw		,lack		,other_7F_opcodes
577 /*80*/ ,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk
578 /*88*/ ,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk
579 /*90*/ ,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk
580 /*98*/ ,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk		,mpyk
581 /*A0*/ ,illegal		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
582 /*A8*/ ,illegal		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
583 /*B0*/ ,illegal		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
584 /*B8*/ ,illegal		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
585 /*C0*/ ,illegal		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
586 /*C8*/ ,illegal		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
587 /*D0*/ ,illegal		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
588 /*D8*/ ,illegal		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
589 /*E0*/ ,illegal		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
590 /*E8*/ ,illegal		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
591 /*F0*/ ,illegal		,illegal	,illegal	,illegal	,banz		,bv			,bioz		,illegal
592 /*F8*/ ,call		,br			,blz		,blez		,bgz		,bgez		,bnz		,bz
593 };
594 
595 static opcode_fn opcode_7F_other[32]=
596 {
597 /*80*/  nop			,dint		,eint		,illegal	,illegal	,illegal	,illegal	,illegal
598 /*88*/ ,abst		,zac		,rovm		,sovm		,cala		,ret		,pac		,apac
599 /*90*/ ,spac		,illegal	,illegal	,illegal	,illegal	,illegal	,illegal	,illegal
600 /*98*/ ,illegal		,illegal	,illegal	,illegal	,push		,pop		,illegal	,illegal
601 };
602 
603 
604 
605 /****************************************************************************
606  * Reset registers to their initial values
607  ****************************************************************************/
tms320c10_reset(void * param)608 void tms320c10_reset (void *param)
609 {
610 	R.PC  = 0;
611 	R.STR  = 0x0fefe;
612 	R.ACC = 0;
613 	R.pending_irq		= TMS320C10_NOT_PENDING;
614 	R.BIO_pending_irq	= TMS320C10_NOT_PENDING;
615 }
616 
617 
618 /****************************************************************************
619  * Shut down CPU emulation
620  ****************************************************************************/
tms320c10_exit(void)621 void tms320c10_exit (void)
622 {
623 	/* nothing to do ? */
624 }
625 
626 
627 /****************************************************************************
628  * Issue an interrupt if necessary
629  ****************************************************************************/
630 
Ext_IRQ(void)631 static int Ext_IRQ(void)
632 {
633 	if (INTM == 0)
634 	{
635 		//logerror("TMS320C10:  EXT INTERRUPT\n");
636 		SET(INTM_FLAG);
637 		R.STACK[0] = R.STACK[1];
638 		R.STACK[1] = R.STACK[2];
639 		R.STACK[2] = R.STACK[3];
640 		R.STACK[3] = R.PC & ADDR_MASK;
641 		R.PC = 0x0002;
642 		R.pending_irq = TMS320C10_NOT_PENDING;
643 		return 3;  /* 3 clock cycles used due to PUSH and DINT operation ? */
644 	}
645 	return 0;
646 }
647 
648 
649 
650 
651 /****************************************************************************
652  * Execute IPeriod. Return 0 if emulation should be stopped
653  ****************************************************************************/
tms320c10_execute(int cycles)654 int tms320c10_execute(int cycles)
655 {
656 	tms320c10_ICount = cycles;
657 
658 	do
659 	{
660 		if (R.pending_irq & TMS320C10_PENDING)
661 		{
662 			int type = (*R.irq_callback)(0);
663 			R.pending_irq |= type;
664 		}
665 
666 		if (R.pending_irq) {
667 			/* Dont service INT if prev instruction was MPY, MPYK or EINT */
668 			if ((opcode_major != 0x6d) || ((opcode_major & 0xe0) != 0x80) || (opcode != 0x7f82))
669 				tms320c10_ICount -= Ext_IRQ();
670 		}
671 
672 		R.PREPC = R.PC;
673 
674 		opcode=M_RDOP(R.PC);
675 		opcode_major = ((opcode & 0x0ff00) >> 8);
676 		opcode_minor = (opcode & 0x0ff);
677 
678 		R.PC++;
679 		if (opcode_major != 0x07f) { /* Do all opcodes except the 7Fxx ones */
680 			tms320c10_ICount -= cycles_main[opcode_major];
681 			(*(opcode_main[opcode_major]))();
682 		}
683 		else { /* Opcode major byte 7Fxx has many opcodes in its minor byte */
684 			opcode_minr = (opcode & 0x001f);
685 			tms320c10_ICount -= cycles_7F_other[opcode_minr];
686 			(*(opcode_7F_other[opcode_minr]))();
687 		}
688 	}
689 	while (tms320c10_ICount>0);
690 
691 	return cycles - tms320c10_ICount;
692 }
693 
694 /****************************************************************************
695  * Get all registers in given buffer
696  ****************************************************************************/
tms320c10_get_context(void * dst)697 unsigned tms320c10_get_context (void *dst)
698 {
699     if( dst )
700         *(tms320c10_Regs*)dst = R;
701     return sizeof(tms320c10_Regs);
702 }
703 
704 /****************************************************************************
705  * Set all registers to given values
706  ****************************************************************************/
tms320c10_set_context(void * src)707 void tms320c10_set_context (void *src)
708 {
709 	if( src )
710 		R = *(tms320c10_Regs*)src;
711 }
712 
713 /****************************************************************************
714  * Return program counter
715  ****************************************************************************/
tms320c10_get_pc(void)716 unsigned tms320c10_get_pc (void)
717 {
718     return R.PC;
719 }
720 
721 
722 /****************************************************************************
723  * Set program counter
724  ****************************************************************************/
tms320c10_set_pc(unsigned val)725 void tms320c10_set_pc (unsigned val)
726 {
727 	R.PC = val;
728 }
729 
730 
731 /****************************************************************************
732  * Return stack pointer
733  ****************************************************************************/
tms320c10_get_sp(void)734 unsigned tms320c10_get_sp (void)
735 {
736 	return R.STACK[3];
737 }
738 
739 
740 /****************************************************************************
741  * Set stack pointer
742  ****************************************************************************/
tms320c10_set_sp(unsigned val)743 void tms320c10_set_sp (unsigned val)
744 {
745 	R.STACK[3] = val;
746 }
747 
748 
749 /****************************************************************************
750  * Return a specific register
751  ****************************************************************************/
tms320c10_get_reg(int regnum)752 unsigned tms320c10_get_reg(int regnum)
753 {
754 	switch( regnum )
755 	{
756 		case TMS320C10_PC: return R.PC;
757 		/* This is actually not a stack pointer, but the stack contents */
758 		case TMS320C10_STK3: return R.STACK[3];
759 		case TMS320C10_ACC: return R.ACC;
760 		case TMS320C10_STR: return R.STR;
761 		case TMS320C10_PREG: return R.Preg;
762 		case TMS320C10_TREG: return R.Treg;
763 		case TMS320C10_AR0: return R.AR[0];
764 		case TMS320C10_AR1: return R.AR[1];
765 		default:
766 			if( regnum <= REG_SP_CONTENTS )
767 			{
768 				unsigned offset = (REG_SP_CONTENTS - regnum);
769 				if( offset < 4 )
770 					return R.STACK[offset];
771 			}
772 	}
773 	return 0;
774 }
775 
776 
777 /****************************************************************************
778  * Set a specific register
779  ****************************************************************************/
tms320c10_set_reg(int regnum,unsigned val)780 void tms320c10_set_reg(int regnum, unsigned val)
781 {
782 	switch( regnum )
783 	{
784 		case TMS320C10_PC: R.PC = val; break;
785 		/* This is actually not a stack pointer, but the stack contents */
786 		case TMS320C10_STK3: R.STACK[3] = val; break;
787 		case TMS320C10_STR: R.STR = val; break;
788 		case TMS320C10_ACC: R.ACC = val; break;
789 		case TMS320C10_PREG: R.Preg = val; break;
790 		case TMS320C10_TREG: R.Treg = val; break;
791 		case TMS320C10_AR0: R.AR[0] = val; break;
792 		case TMS320C10_AR1: R.AR[1] = val; break;
793 		default:
794 			if( regnum <= REG_SP_CONTENTS )
795 			{
796 				unsigned offset = (REG_SP_CONTENTS - regnum);
797 				if( offset < 4 )
798 					R.STACK[offset] = val;
799 			}
800     }
801 }
802 
803 
804 /****************************************************************************
805  * Set NMI line state
806  ****************************************************************************/
tms320c10_set_nmi_line(int state)807 void tms320c10_set_nmi_line(int state)
808 {
809 	/* TMS320C10 does not have a NMI line */
810 }
811 
812 /****************************************************************************
813  * Set IRQ line state
814  ****************************************************************************/
tms320c10_set_irq_line(int irqline,int state)815 void tms320c10_set_irq_line(int irqline, int state)
816 {
817 	if (irqline == TMS320C10_ACTIVE_INT)
818 	{
819 		R.irq_state = state;
820 		if (state == CLEAR_LINE) R.pending_irq &= ~TMS320C10_PENDING;
821 		if (state == ASSERT_LINE) R.pending_irq |= TMS320C10_PENDING;
822 	}
823 	if (irqline == TMS320C10_ACTIVE_BIO)
824 	{
825 		if (state == CLEAR_LINE) R.BIO_pending_irq &= ~TMS320C10_PENDING;
826 		if (state == ASSERT_LINE) R.BIO_pending_irq |= TMS320C10_PENDING;
827 	}
828 }
829 
tms320c10_set_irq_callback(int (* callback)(int irqline))830 void tms320c10_set_irq_callback(int (*callback)(int irqline))
831 {
832 	R.irq_callback = callback;
833 }
834 
835 /****************************************************************************
836  * Return a formatted string for a register
837  ****************************************************************************/
tms320c10_info(void * context,int regnum)838 const char *tms320c10_info(void *context, int regnum)
839 {
840     switch( regnum )
841 	{
842 		case CPU_INFO_NAME: return "320C10";
843         case CPU_INFO_FAMILY: return "Texas Instruments 320C10";
844 		case CPU_INFO_VERSION: return "1.02";
845         case CPU_INFO_FILE: return __FILE__;
846         case CPU_INFO_CREDITS: return "Copyright (C) 1999 by Quench";
847     }
848 	return "";
849 }
850 
tms320c10_dasm(char * buffer,unsigned pc)851 unsigned tms320c10_dasm(char *buffer, unsigned pc)
852 {
853 	sprintf( buffer, "$%04X", TMS320C10_RDOP(pc) );
854 	return 2;
855 }
856 
857