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, < },{1, <d },{1, <a },{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