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