1 /*
2 99xxcore.h : generic tms99xx emulation
3
4 The TMS99XX_MODEL switch tell which emulator we want to build. Set the switch, then include
5 99xxcore.h, and you will have an emulator for this processor.
6
7 Only tms9900, tms9980a/9981, and tms9995 work OK for now. Note that tms9995 has not been tested
8 extensively.
9
10 I think all software aspects of tms9940, tms9985 and tms9989 are implemented (though there
11 must be some mistakes, particularily in tms9940 BCD support). You'll just have to implement
12 bus interfaces, provided you know them. (I don't...)
13
14 Original tms9900 emulator by Edward Swartz
15 Smoothed out by Raphael Nabet
16 Originally converted for Mame by M.Coates
17 Processor timing, support for tms9980 and tms9995, and many bug fixes by R Nabet
18 */
19
20 /*
21 tms9900 is derived from the TI990/x minicomputer series (with multi-chip processors, except with
22 cheaper or later models, which used microprocessors). However, tms99xx (and even extension-less
23 tms99xxx) only implement a reduced subset of the huge instruction set available on big TI990
24 systems.
25
26 AFAIK, tms9900, tms9980, and tms9985 have exactly the same programming model, and are actually
27 the same CPU with different bus interfaces. The former affirmation is (almost) true with
28 tms9940, so I guess the later is true, too. (The only problem with tms9940 is I have no idea
29 what its bus interfaces are - I have a pinout, but it does not help much, although it is obvious
30 that the beast is a microcontroller.) tms9985 had on-chip RAM and timer, like tms9995, although
31 I don't know how the memory and CRU were mapped exactly.
32
33 tms9989 is mostly alien to me. I assumed it was more related to tms9900 than tms9995, although
34 it has most of the additionnal features tms9995 has.
35
36 tms9995 belongs to another generation. As a matter of fact, it quite faster than tms9900.
37
38 tms99xxx include all tms9995 advances, and add some advances of their own. I know they support
39 many extra opcodes (84 instructions types on tms99105a, vs. 69 on tms9900), and support
40 privileges (i.e. supervisor mode), flags in multiprocessor environment, 32-bit operations...
41 There was yet other features (Macrostore to define custom instructions, op code compression...),
42 which are completely alien to me.
43
44 I have written code to recognize every tms99xxx opcode, and all other TI990 instructions I have
45 heard of. I cannot complete this code, since I have no documentation on tms99xxx. I am not
46 even sure the instruction set I guessed for tms99xxx is correct. Also, the proposed meaning for
47 these extra memnonics could be wrong.
48
49 References :
50 * 9900 family systems design, chapter 6, 7, 8
51 * TMS 9980A/ TMS 9981 Product Data Book
52 * TMS 9995 16-Bit Microcomputer Data Manual
53
54 Tons of thanks to the guy who posted these, whoever he is...
55 <http://www.stormaster.com/Spies/arcade/simulation/processors/index.html>
56 */
57
58 /* Set this to 1 to support HOLD_LINE */
59 /* This is a weird HOLD_LINE, actually : we hold the interrupt line only until IAQ
60 (instruction acquisition) is enabled. Well, this scheme could possibly exist on
61 a tms9900-based system, unlike a real HOLD_LINE. (OK, this is just a pretext, I was just too
62 lazy to implement a true HOLD_LINE ;-) .) */
63 /* BTW, this only works with tms9900 ! */
64 #define SILLY_INTERRUPT_HACK 0
65
66 #if SILLY_INTERRUPT_HACK
67 #define IRQ_MAGIC_LEVEL -2
68 #endif
69
70
71 #include "memory.h"
72 #include "tms9900.h"
73 #include <math.h>
74
75 #include <retro_inline.h>
76
77
78 #if (TMS99XX_MODEL == TMS9900_ID)
79
80 #define TMS99XX_ICOUNT tms9900_ICount
81 #define TMS99XX_RESET tms9900_reset
82 #define TMS99XX_EXIT tms9900_exit
83 #define TMS99XX_EXECUTE tms9900_execute
84 #define TMS99XX_GET_CONTEXT tms9900_get_context
85 #define TMS99XX_SET_CONTEXT tms9900_set_context
86 #define TMS99XX_GET_PC tms9900_get_pc
87 #define TMS99XX_SET_PC tms9900_set_pc
88 #define TMS99XX_GET_SP tms9900_get_sp
89 #define TMS99XX_SET_SP tms9900_set_sp
90 #define TMS99XX_GET_REG tms9900_get_reg
91 #define TMS99XX_SET_REG tms9900_set_reg
92 #define TMS99XX_SET_IRQ_CALLBACK tms9900_set_irq_callback
93 #define TMS99XX_INFO tms9900_info
94 #define TMS99XX_DASM tms9900_dasm
95
96 #define TMS99XX_CPU_NAME "TMS9900"
97
98 #elif (TMS99XX_MODEL == TMS9940_ID)
99
100 #define TMS99XX_ICOUNT tms9940_ICount
101 #define TMS99XX_RESET tms9940_reset
102 #define TMS99XX_EXIT tms9940_exit
103 #define TMS99XX_EXECUTE tms9940_execute
104 #define TMS99XX_GET_CONTEXT tms9940_get_context
105 #define TMS99XX_SET_CONTEXT tms9940_set_context
106 #define TMS99XX_GET_PC tms9940_get_pc
107 #define TMS99XX_SET_PC tms9940_set_pc
108 #define TMS99XX_GET_SP tms9940_get_sp
109 #define TMS99XX_SET_SP tms9940_set_sp
110 #define TMS99XX_GET_REG tms9940_get_reg
111 #define TMS99XX_SET_REG tms9940_set_reg
112 #define TMS99XX_SET_IRQ_CALLBACK tms9940_set_irq_callback
113 #define TMS99XX_INFO tms9940_info
114 #define TMS99XX_DASM tms9940_dasm
115
116 #define TMS99XX_CPU_NAME "TMS9940"
117
118 #error "tms9940 is not yet supported"
119
120 #elif (TMS99XX_MODEL == TMS9980_ID)
121
122 #define TMS99XX_ICOUNT tms9980a_ICount
123 #define TMS99XX_RESET tms9980a_reset
124 #define TMS99XX_EXIT tms9980a_exit
125 #define TMS99XX_EXECUTE tms9980a_execute
126 #define TMS99XX_GET_CONTEXT tms9980a_get_context
127 #define TMS99XX_SET_CONTEXT tms9980a_set_context
128 #define TMS99XX_GET_PC tms9980a_get_pc
129 #define TMS99XX_SET_PC tms9980a_set_pc
130 #define TMS99XX_GET_SP tms9980a_get_sp
131 #define TMS99XX_SET_SP tms9980a_set_sp
132 #define TMS99XX_GET_REG tms9980a_get_reg
133 #define TMS99XX_SET_REG tms9980a_set_reg
134 #define TMS99XX_SET_IRQ_CALLBACK tms9980a_set_irq_callback
135 #define TMS99XX_INFO tms9980a_info
136 #define TMS99XX_DASM tms9980a_dasm
137
138 #define TMS99XX_CPU_NAME "TMS9980A/TMS9981"
139
140 #elif (TMS99XX_MODEL == TMS9985_ID)
141
142 #define TMS99XX_ICOUNT tms9985_ICount
143 #define TMS99XX_RESET tms9985_reset
144 #define TMS99XX_EXIT tms9985_exit
145 #define TMS99XX_EXECUTE tms9985_execute
146 #define TMS99XX_GET_CONTEXT tms9985_get_context
147 #define TMS99XX_SET_CONTEXT tms9985_set_context
148 #define TMS99XX_GET_PC tms9985_get_pc
149 #define TMS99XX_SET_PC tms9985_set_pc
150 #define TMS99XX_GET_SP tms9985_get_sp
151 #define TMS99XX_SET_SP tms9985_set_sp
152 #define TMS99XX_GET_REG tms9985_get_reg
153 #define TMS99XX_SET_REG tms9985_set_reg
154 #define TMS99XX_SET_IRQ_CALLBACK tms9985_set_irq_callback
155 #define TMS99XX_INFO tms9985_info
156 #define TMS99XX_DASM tms9985_dasm
157
158 #define TMS99XX_CPU_NAME "TMS9985"
159
160 #error "tms9985 is not yet supported"
161
162 #elif (TMS99XX_MODEL == TMS9989_ID)
163
164 #define TMS99XX_ICOUNT tms9989_ICount
165 #define TMS99XX_RESET tms9989_reset
166 #define TMS99XX_EXIT tms9989_exit
167 #define TMS99XX_EXECUTE tms9989_execute
168 #define TMS99XX_GET_CONTEXT tms9989_get_context
169 #define TMS99XX_SET_CONTEXT tms9989_set_context
170 #define TMS99XX_GET_PC tms9989_get_pc
171 #define TMS99XX_SET_PC tms9989_set_pc
172 #define TMS99XX_GET_SP tms9989_get_sp
173 #define TMS99XX_SET_SP tms9989_set_sp
174 #define TMS99XX_GET_REG tms9989_get_reg
175 #define TMS99XX_SET_REG tms9989_set_reg
176 #define TMS99XX_SET_IRQ_CALLBACK tms9989_set_irq_callback
177 #define TMS99XX_INFO tms9989_info
178 #define TMS99XX_DASM tms9989_dasm
179
180 #define TMS99XX_CPU_NAME "TMS9989"
181
182 #error "tms9989 is not yet supported"
183
184 #elif (TMS99XX_MODEL == TMS9995_ID)
185
186 #define TMS99XX_ICOUNT tms9995_ICount
187 #define TMS99XX_RESET tms9995_reset
188 #define TMS99XX_EXIT tms9995_exit
189 #define TMS99XX_EXECUTE tms9995_execute
190 #define TMS99XX_GET_CONTEXT tms9995_get_context
191 #define TMS99XX_SET_CONTEXT tms9995_set_context
192 #define TMS99XX_GET_PC tms9995_get_pc
193 #define TMS99XX_SET_PC tms9995_set_pc
194 #define TMS99XX_GET_SP tms9995_get_sp
195 #define TMS99XX_SET_SP tms9995_set_sp
196 #define TMS99XX_GET_REG tms9995_get_reg
197 #define TMS99XX_SET_REG tms9995_set_reg
198 #define TMS99XX_SET_IRQ_CALLBACK tms9995_set_irq_callback
199 #define TMS99XX_INFO tms9995_info
200 #define TMS99XX_DASM tms9995_dasm
201
202 #define TMS99XX_CPU_NAME "TMS9995"
203
204 #elif (TMS99XX_MODEL == TMS99105A_ID)
205
206 #define TMS99XX_ICOUNT tms99105a_ICount
207 #define TMS99XX_RESET tms99105a_reset
208 #define TMS99XX_EXIT tms99105a_exit
209 #define TMS99XX_EXECUTE tms99105a_execute
210 #define TMS99XX_GET_CONTEXT tms99105a_get_context
211 #define TMS99XX_SET_CONTEXT tms99105a_set_context
212 #define TMS99XX_GET_PC tms99105a_get_pc
213 #define TMS99XX_SET_PC tms99105a_set_pc
214 #define TMS99XX_GET_SP tms99105a_get_sp
215 #define TMS99XX_SET_SP tms99105a_set_sp
216 #define TMS99XX_GET_REG tms99105a_get_reg
217 #define TMS99XX_SET_REG tms99105a_set_reg
218 #define TMS99XX_SET_IRQ_CALLBACK tms99105a_set_irq_callback
219 #define TMS99XX_INFO tms99105a_info
220 #define TMS99XX_DASM tms99105a_dasm
221
222 #define TMS99XX_CPU_NAME "TMS99105A"
223
224 #error "tms99105a is not yet supported"
225
226 #elif (TMS99XX_MODEL == TMS99110A_ID)
227
228 #define TMS99XX_ICOUNT tms99110a_ICount
229 #define TMS99XX_RESET tms99110a_reset
230 #define TMS99XX_EXIT tms99110a_exit
231 #define TMS99XX_EXECUTE tms99110a_execute
232 #define TMS99XX_GET_CONTEXT tms99110a_get_context
233 #define TMS99XX_SET_CONTEXT tms99110a_set_context
234 #define TMS99XX_GET_PC tms99110a_get_pc
235 #define TMS99XX_SET_PC tms99110a_set_pc
236 #define TMS99XX_GET_SP tms99110a_get_sp
237 #define TMS99XX_SET_SP tms99110a_set_sp
238 #define TMS99XX_GET_REG tms99110a_get_reg
239 #define TMS99XX_SET_REG tms99110a_set_reg
240 #define TMS99XX_SET_IRQ_CALLBACK tms99110a_set_irq_callback
241 #define TMS99XX_INFO tms99110a_info
242 #define TMS99XX_DASM tms99110a_dasm
243
244 #define TMS99XX_CPU_NAME "TMS99110A"
245
246 #error "tms99110a is not yet supported"
247
248 #endif
249
250
251 static INLINE void execute(UINT16 opcode);
252
253 static void external_instruction_notify(int ext_op_ID);
254 static UINT16 fetch(void);
255 static UINT16 decipheraddr(UINT16 opcode);
256 static UINT16 decipheraddrbyte(UINT16 opcode);
257 static void contextswitch(UINT16 addr);
258
259 static void field_interrupt(void);
260
261 /***************************/
262 /* Mame Interface Routines */
263 /***************************/
264
265 int TMS99XX_ICOUNT = 0;
266
267
268 /* tms9900 ST register bits. */
269
270 /* These bits are set by every compare, move and arithmetic or logical operation : */
271 /* (Well, COC, CZC and TB only set the E bit, but these are kind of exceptions.) */
272 #define ST_LGT 0x8000 /* Logical Greater Than (strictly) */
273 #define ST_AGT 0x4000 /* Arithmetical Greater Than (strictly) */
274 #define ST_EQ 0x2000 /* Equal */
275
276 /* These bits are set by arithmetic operations, when it makes sense to update them. */
277 #define ST_C 0x1000 /* Carry */
278 #define ST_OV 0x0800 /* OVerflow (overflow with operations on signed integers, */
279 /* and when the result of a 32bits:16bits division cannot fit in a 16-bit word.) */
280
281 /* This bit is set by move and arithmetic operations WHEN THEY USE BYTE OPERANDS. */
282 #define ST_OP 0x0400 /* Odd Parity */
283
284 #if (TMS99XX_MODEL != TMS9940_ID)
285
286 /* This bit is set by the XOP instruction. */
287 #define ST_X 0x0200 /* Xop */
288
289 #endif
290
291 #if (TMS99XX_MODEL == TMS9940_ID)
292
293 /* This bit is set by arithmetic operations to support BCD */
294 #define ST_DC 0x0100 /* Digit Carry */
295
296 #endif
297
298 #if (TMS99XX_MODEL == TMS99105A_ID)
299
300 /* This bit is set in user (i.e. non-supervisor) mode */
301 #define ST_PRIVILEGED 0x0100
302
303 #endif
304
305 #if (TMS99XX_MODEL >= TMS9995_ID)
306
307 /* This bit is set in TMS9995 and later chips to generate a level-2 interrupt when the Overflow
308 status bit is set */
309 #define ST_OV_EN 0x0020 /* OVerflow interrupt ENable */
310
311 #endif
312
313 /* On models before TMS9995 (TMS9989 ?), unused ST bits are always forced to 0, so we define
314 a ST_MASK */
315 #if TMS99XX_MODEL == TMS9940_ID
316
317 #define ST_MASK 0xFD03
318
319 #elif TMS99XX_MODEL <= TMS9985_ID
320
321 #define ST_MASK 0xFE0F
322
323 #endif
324
325
326 /* Offsets for registers. */
327 #define R0 0
328 #define R1 2
329 #define R2 4
330 #define R3 6
331 #define R4 8
332 #define R5 10
333 #define R6 12
334 #define R7 14
335 #define R8 16
336 #define R9 18
337 #define R10 20
338 #define R11 22
339 #define R12 24
340 #define R13 26
341 #define R14 28
342 #define R15 30
343
344 typedef struct
345 {
346 /* "actual" tms9900 registers : */
347 UINT16 WP; /* Workspace pointer */
348 UINT16 PC; /* Program counter */
349 UINT16 STATUS; /* STatus register */
350
351 /* Now, data used for emulation */
352 UINT16 IR; /* Instruction register, with the currently parsed opcode */
353
354 int interrupt_pending; /* true if an interrupt must be honored... */
355
356 int load_state; /* nonzero if the LOAD* line is active (low) */
357
358 #if ((TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID))
359 /* On tms9900, we cache the state of INTREQ* and IC0-IC3 here */
360 /* On tms9980/9981, we translate the state of IC0-IC2 to the equivalent state for a tms9900,
361 and store the result here */
362 int irq_level; /* when INTREQ* is active, interrupt level on IC0-IC3 ; else always 16 */
363 int irq_state; /* nonzero if the INTREQ* line is active (low) */
364 #elif (TMS99XX_MODEL == TMS9995_ID)
365 /* tms9995 is quite different : it latches the interrupt inputs */
366 int irq_level; /* We store the level of the request with the highest level here */
367 int int_state; /* interrupt lines state */
368 int int_latch; /* interrupt latches state */
369 #endif
370
371 /* interrupt callback */
372 /* note that this callback is used by tms9900_set_irq_line() and tms9980a_set_irq_line() to
373 retreive the value on IC0-IC3 (non-standard behaviour) */
374 int (*irq_callback)(int irq_line);
375
376 int IDLE; /* nonzero if processor is IDLE - i.e waiting for interrupt while writing
377 special data on CRU bus */
378
379 #if (TMS99XX_MODEL == TMS9985_ID) || (TMS99XX_MODEL == TMS9995_ID)
380 unsigned char RAM[256]; /* on-chip RAM (yes, sir !) */
381 #endif
382
383 #if (TMS99XX_MODEL == TMS9995_ID)
384 /* on-chip event counter/timer*/
385 int decrementer_enabled;
386 UINT16 decrementer_interval;
387 UINT16 decrementer_count; /* used in event counter mode*/
388 void *timer; /* used in timer mode */
389 #endif
390
391 #if (TMS99XX_MODEL == TMS9995_ID)
392 /* additionnal registers */
393 UINT16 flag; /* flag register */
394 int MID_flag; /* MID flag register */
395 #endif
396
397 #if (TMS99XX_MODEL == TMS9995_ID)
398 /* chip config, which can be set on reset */
399 int memory_wait_states_byte;
400 int memory_wait_states_word;
401 #endif
402 } tms99xx_Regs;
403
404 static tms99xx_Regs I =
405 {
406 0,0,0,0, /* don't care */
407 0, /* no pending interrupt */
408 0, /* LOAD* inactive */
409 16, 0, /* INTREQ* inactive */
410 };
411 static UINT8 lastparity; /* rather than handling ST_OP directly, we copy the last value which
412 would set it here */
413 /* Some instructions (i.e. XOP, BLWP, and MID) disable interrupt recognition until another
414 instruction is executed : so they set this flag */
415 static int disable_interrupt_recognition = 0;
416
417 #if (TMS99XX_MODEL == TMS9995_ID)
418 static void reset_decrementer(void);
419 #endif
420
421 #if (TMS99XX_MODEL == TMS9900_ID)
422 /*16-bit data bus, 16-bit address bus*/
423 /*Note that tms9900 actually never accesses a single byte : when performing byte operations,
424 it reads a 16-bit word, changes the revelant byte, then write a complete word. You should
425 remember this when writing memory handlers.*/
426 /*This does not apply to tms9995 and tms99xxx, but does apply to tms9980 (see below).*/
427
428 #define readword(addr) cpu_readmem16bew_word(addr)
429 #define writeword(addr,data) cpu_writemem16bew_word((addr), (data))
430
431 #define readbyte(addr) cpu_readmem16bew(addr)
432 #define writebyte(addr,data) cpu_writemem16bew((addr),(data))
433
434 #elif (TMS99XX_MODEL == TMS9980_ID)
435 /*8-bit data bus, 14-bit address*/
436 /*Note that tms9980 never accesses a single byte (however crazy it may seem). Although this
437 makes memory access slower, I have emulated this feature, because if I did otherwise,
438 there would be some implementation problems in some driver sooner or later.*/
439
440 /*Macros instead of true 14-bit handlers. You may want to change this*/
441 #define cpu_readmem14(addr) cpu_readmem16((addr) & 0x3fff)
442 #define cpu_writemem14(addr, data) cpu_writemem16((addr) & 0x3fff, data)
443
444 #define readword(addr) ( TMS99XX_ICOUNT -= 2, (cpu_readmem14(addr) << 8) + cpu_readmem14((addr)+1) )
445 #define writeword(addr,data) { TMS99XX_ICOUNT -= 2; cpu_writemem14((addr), (data) >> 8); cpu_writemem14((addr) + 1, (data) & 0xff); }
446
447 #if 0
448 #define readbyte(addr) (TMS99XX_ICOUNT -= 2, cpu_readmem14(addr))
449 #define writebyte(addr,data) { TMS99XX_ICOUNT -= 2; cpu_writemem14((addr),(data)); }
450 #else
451 /*This is how it really works*/
452 /*Note that every writebyte must match a readbyte (which is the case on a real-world tms9980)*/
453 static int extra_byte;
454
readbyte(int addr)455 static int readbyte(int addr)
456 {
457 TMS99XX_ICOUNT -= 2;
458 if (addr & 1)
459 {
460 extra_byte = cpu_readmem14(addr-1);
461 return cpu_readmem14(addr);
462 }
463 else
464 {
465 int val = cpu_readmem14(addr);
466 extra_byte = cpu_readmem14(addr+1);
467 return val;
468 }
469 }
writebyte(int addr,int data)470 static void writebyte (int addr, int data)
471 {
472 TMS99XX_ICOUNT -= 2;
473 if (addr & 1)
474 {
475 extra_byte = cpu_readmem14(addr-1);
476
477 cpu_writemem14(addr-1, extra_byte);
478 cpu_writemem14(addr, data);
479 }
480 else
481 {
482 extra_byte = cpu_readmem14(addr+1);
483
484 cpu_writemem14(addr, data);
485 cpu_writemem14(addr+1, extra_byte);
486 }
487 }
488 #endif
489
490 #elif (TMS99XX_MODEL == TMS9995_ID)
491 /*8-bit external data bus, with on-chip 16-bit RAM, and 16-bit address bus*/
492 /*The code is complex, so we use functions rather than macros*/
493
494 /* Why aren't these in memory.h ??? */
495 #ifdef MSB_FIRST
496 #define BYTE_XOR_BE(a) (a)
497 #else
498 #define BYTE_XOR_BE(a) ((a) ^ 1)
499 #endif
500
readword(int addr)501 static int readword(int addr)
502 {
503 if (addr < 0xf000)
504 {
505 TMS99XX_ICOUNT -= I.memory_wait_states_word;
506 return (cpu_readmem16(addr) << 8) + cpu_readmem16(addr + 1);
507 }
508 else if (addr < 0xf0fc)
509 {
510 return READ_WORD(& I.RAM[addr - 0xf000]);
511 }
512 else if (addr < 0xfffa)
513 {
514 TMS99XX_ICOUNT -= I.memory_wait_states_word;
515 return (cpu_readmem16(addr) << 8) + cpu_readmem16(addr + 1);
516 }
517 else if (addr < 0xfffc)
518 {
519 /* read decrementer */
520 if (I.flag & 1)
521 /* event counter mode */
522 return I.decrementer_count;
523 else if (I.timer)
524 /* timer mode, timer enabled */
525 //return ceil(TIME_TO_CYCLES(cpu_getactivecpu(), timer_timeleft(I.timer)) / 16);
526 return TIME_TO_CYCLES(cpu_getactivecpu(), timer_timeleft(I.timer)) / 16;
527 else
528 /* timer mode, timer disabled */
529 return 0;
530 }
531 else
532 {
533 return READ_WORD(& I.RAM[addr - 0xff00]);
534 }
535 }
536
writeword(int addr,int data)537 static void writeword (int addr, int data)
538 {
539 if (addr < 0xf000)
540 {
541 TMS99XX_ICOUNT -= I.memory_wait_states_word;
542 cpu_writemem16(addr, data >> 8);
543 cpu_writemem16(addr + 1, data & 0xff);
544 }
545 else if (addr < 0xf0fc)
546 {
547 WRITE_WORD(& I.RAM[addr - 0xf000], data);
548 }
549 else if (addr < 0xfffa)
550 {
551 TMS99XX_ICOUNT -= I.memory_wait_states_word;
552 cpu_writemem16(addr, data >> 8);
553 cpu_writemem16(addr + 1, data & 0xff);
554 }
555 else if (addr < 0xfffc)
556 {
557 /* write decrementer */
558 I.decrementer_interval = data;
559 reset_decrementer();
560 }
561 else
562 {
563 WRITE_WORD(& I.RAM[addr - 0xff00], data);
564 }
565 }
566
readbyte(int addr)567 static int readbyte(int addr)
568 {
569 if (addr < 0xf000)
570 {
571 TMS99XX_ICOUNT -= I.memory_wait_states_byte;
572 return cpu_readmem16(addr);
573 }
574 else if (addr < 0xf0fc)
575 {
576 return I.RAM[BYTE_XOR_BE(addr - 0xf000)];
577 }
578 else if (addr < 0xfffa)
579 {
580 TMS99XX_ICOUNT -= I.memory_wait_states_byte;
581 return cpu_readmem16(addr);;
582 }
583 else if (addr < 0xfffc)
584 {
585 /* read decrementer */
586 int value;
587
588 if (I.flag & 1)
589 /* event counter mode */
590 value = I.decrementer_count;
591 else if (I.timer)
592 /* timer mode, timer enabled */
593 //value = ceil(TIME_TO_CYCLES(cpu_getactivecpu(), timer_timeleft(I.timer)) / 16);
594 value = TIME_TO_CYCLES(cpu_getactivecpu(), timer_timeleft(I.timer)) / 16;
595 else
596 /* timer mode, timer disabled */
597 value = 0;
598
599 if (addr & 1)
600 return (value & 0xFF);
601 else
602 return (value >> 8);
603 }
604 else
605 {
606 return I.RAM[BYTE_XOR_BE(addr - 0xff00)];
607 }
608 }
609
writebyte(int addr,int data)610 static void writebyte (int addr, int data)
611 {
612 if (addr < 0xf000)
613 {
614 TMS99XX_ICOUNT -= I.memory_wait_states_byte;
615 cpu_writemem16(addr, data);
616 }
617 else if (addr < 0xf0fc)
618 {
619 I.RAM[BYTE_XOR_BE(addr - 0xf000)] = data;
620 }
621 else if (addr < 0xfffa)
622 {
623 TMS99XX_ICOUNT -= I.memory_wait_states_byte;
624 cpu_writemem16(addr, data);
625 }
626 else if (addr < 0xfffc)
627 {
628 /* write decrementer */
629 /* Note that a byte write to tms9995 timer messes everything up. */
630 I.decrementer_interval = (data << 8) | data;
631 reset_decrementer();
632 }
633 else
634 {
635 I.RAM[BYTE_XOR_BE(addr - 0xff00)] = data;
636 }
637 }
638
639 #else
640
641 #error "memory access not implemented"
642
643 #endif
644
645 #define READREG(reg) readword(I.WP+reg)
646 #define WRITEREG(reg,data) writeword(I.WP+reg,data)
647
648 /* Interrupt mask */
649 #if (TMS99XX_MODEL != TMS9940_ID)
650 #define IMASK (I.STATUS & 0x0F)
651 #else
652 #define IMASK (I.STATUS & 0x03)
653 #endif
654
655 /*
656 CYCLES macro : you provide timings for tms9900 and tms9995, and the macro chooses for you.
657
658 BTW, I have no idea what the timings are for tms9989 and tms99xxx...
659 */
660 #if TMS99XX_MODEL <= TMS9989_ID
661 /* Use TMS9900/TMS9980 timings*/
662 #define CYCLES(a,b) TMS99XX_ICOUNT -= a
663 #else
664 /* Use TMS9995 timings*/
665 #define CYCLES(a,b) TMS99XX_ICOUNT -= b*4
666 #endif
667
668 #if (TMS99XX_MODEL == TMS9995_ID)
669
670 static void set_flag0(int val);
671 static void set_flag1(int val);
672
673 #endif
674
675 /************************************************************************
676 * Status register functions
677 ************************************************************************/
678 #include "99xxstat.h"
679
680 /**************************************************************************/
681
682 /*
683 TMS9900 hard reset
684 */
TMS99XX_RESET(void * param)685 void TMS99XX_RESET(void *param)
686 {
687 contextswitch(0x0000);
688
689 I.STATUS = 0; /* TMS9980 and TMS9995 Data Book say so */
690 setstat();
691
692 I.IDLE = 0; /* clear IDLE condition */
693
694 #if (TMS99XX_MODEL == TMS9995_ID)
695 /* we can ask at reset time that the CPU always generates one wait state automatically */
696 if (param == NULL)
697 { /* if no param, the default is currently "wait state added" */
698 I.memory_wait_states_byte = 4;
699 I.memory_wait_states_word = 12;
700 }
701 else
702 {
703 I.memory_wait_states_byte = (((tms9995reset_param *) param)->auto_wait_state) ? 4 : 0;
704 I.memory_wait_states_word = (((tms9995reset_param *) param)->auto_wait_state) ? 12 : 4;
705 }
706
707 I.MID_flag = 0;
708
709 /* Clear flag bits 0 & 1 */
710 set_flag0(0);
711 set_flag1(0);
712
713 /* Clear internal interupt latches */
714 I.int_latch = 0;
715 I.flag &= 0xFFE3;
716 #endif
717
718 /* The ST register and interrupt latches changed, didn't it ? */
719 field_interrupt();
720
721 CYCLES(26, 14);
722 }
723
TMS99XX_EXIT(void)724 void TMS99XX_EXIT(void)
725 {
726 /* nothing to do ? */
727 }
728
TMS99XX_EXECUTE(int cycles)729 int TMS99XX_EXECUTE(int cycles)
730 {
731 TMS99XX_ICOUNT = cycles;
732
733 do
734 {
735 if (I.IDLE)
736 { /* IDLE instruction has halted execution */
737 external_instruction_notify(2);
738 CYCLES(2, 2); /* 2 cycles per CRU write */
739 }
740 else
741 { /* we execute an instruction */
742 disable_interrupt_recognition = 0; /* default value */
743 I.IR = fetch();
744 execute(I.IR);
745
746 #if (TMS99XX_MODEL >= TMS9995_ID)
747 /* Note that TI had some problem implementing this... I don't know if this feature works on
748 a real-world TMS9995. */
749 if ((I.STATUS & ST_OV_EN) && (I.STATUS & ST_OV) && (I.irq_level > 2))
750 I.irq_level = 2; /* interrupt request */
751 #endif
752 }
753
754 /*
755 We handle interrupts here because :
756 a) LOAD and level-0 (reset) interrupts are non-maskable, so, AFAIK, if the LOAD* line or
757 INTREQ* line (with IC0-3 == 0) remain active, we will execute repeatedly the first
758 instruction of the interrupt routine.
759 b) if we did otherwise, we could have weird, buggy behavior if IC0-IC3 changed more than
760 once in too short a while (i.e. before tms9900 executes another instruction). Yes, this
761 is rather pedantic, the probability is really small.
762 */
763 if (I.interrupt_pending)
764 {
765 int level;
766
767 #if SILLY_INTERRUPT_HACK
768 if (I.irq_level == IRQ_MAGIC_LEVEL)
769 {
770 level = (* I.irq_callback)(0);
771 if (I.irq_state)
772 { /* if callback didn't clear the line */
773 I.irq_level = level;
774 if (level > IMASK)
775 I.interrupt_pending = 0;
776 }
777 }
778 else
779 #endif
780 level = I.irq_level;
781
782 if (I.load_state)
783 { /* LOAD has the highest priority */
784
785 contextswitch(0xFFFC); /* load vector, save PC, WP and ST */
786
787 I.STATUS &= 0xFFF0; /* clear mask */
788
789 /* clear IDLE status if necessary */
790 I.IDLE = 0;
791
792 CYCLES(22, 14);
793 }
794 /* all TMS9900 chips I know do not honor interrupts after XOP, BLWP or MID (after any
795 interrupt-like instruction, actually) */
796 else if (! disable_interrupt_recognition)
797 {
798 if (level <= IMASK)
799 { /* a maskable interrupt is honored only if its level isn't greater than IMASK */
800
801 contextswitch(level*4); /* load vector, save PC, WP and ST */
802
803 /* change interrupt mask */
804 if (level)
805 {
806 I.STATUS = (I.STATUS & 0xFFF0) | (level -1); /* decrement mask */
807 I.interrupt_pending = 0; /* as a consequence, the interrupt request will be subsequently ignored */
808 }
809 else
810 I.STATUS &= 0xFFF0; /* clear mask (is this correct ???) */
811
812 #if (TMS99XX_MODEL == TMS9995_ID)
813 I.STATUS &= 0xFE00;
814 #endif
815
816 /* clear IDLE status if necessary */
817 I.IDLE = 0;
818
819 #if (TMS99XX_MODEL == TMS9995_ID)
820 /* Clear bit in latch */
821 /* I think tms9989 does this, too */
822 if (level != 2)
823 { /* Only do this on level 1, 3, 4 interrupts */
824 int mask = 1 << level;
825 int flag_mask = (level == 1) ? 4 : mask;
826
827 I.int_latch &= ~ mask;
828 I.flag &= ~ flag_mask;
829
830 /* unlike tms9900, we can call the callback */
831 if (level == 1)
832 (* I.irq_callback)(0);
833 else if (level == 4)
834 (* I.irq_callback)(1);
835 }
836 #endif
837
838 CYCLES(22, 14);
839 }
840 else
841 #if SILLY_INTERRUPT_HACK
842 if (I.interrupt_pending) /* we may have just cleared this */
843 #endif
844 {
845 //logerror("tms9900.c : the interrupt_pending flag was set incorrectly\n");
846 I.interrupt_pending = 0;
847 }
848 }
849 }
850
851 } while (TMS99XX_ICOUNT > 0);
852
853 return cycles - TMS99XX_ICOUNT;
854 }
855
TMS99XX_GET_CONTEXT(void * dst)856 unsigned TMS99XX_GET_CONTEXT(void *dst)
857 {
858 setstat();
859
860 if( dst )
861 *(tms99xx_Regs*)dst = I;
862
863 return sizeof(tms99xx_Regs);
864 }
865
TMS99XX_SET_CONTEXT(void * src)866 void TMS99XX_SET_CONTEXT(void *src)
867 {
868 if( src )
869 {
870 I = *(tms99xx_Regs*)src;
871 /* We have to make additionnal checks this, because Mame debugger can foolishly initialize
872 the context to all 0s */
873 #if (TMS99XX_MODEL == TMS9900_ID)
874 if (! I.irq_state)
875 I.irq_level = 16;
876 #elif ((TMS99XX_MODEL == TMS9980_ID) || (TMS99XX_MODEL == TMS9995_ID))
877 /* Our job is simpler, since there is no level-0 request... */
878 if (! I.irq_level)
879 I.irq_level = 16;
880 #else
881 #warning "You may want to have a look at this problem"
882 #endif
883
884 getstat(); /* set last_parity */
885 }
886 }
887
TMS99XX_GET_PC(void)888 unsigned TMS99XX_GET_PC(void)
889 {
890 return I.PC;
891 }
892
TMS99XX_SET_PC(unsigned val)893 void TMS99XX_SET_PC(unsigned val)
894 {
895 I.PC = val;
896 }
897
898 /*
899 Note : the WP register actually has nothing to do with a stack.
900
901 To make this even weirder, some later versions of the TMS9900 do have a processor stack.
902 */
TMS99XX_GET_SP(void)903 unsigned TMS99XX_GET_SP(void)
904 {
905 return I.WP;
906 }
907
TMS99XX_SET_SP(unsigned val)908 void TMS99XX_SET_SP(unsigned val)
909 {
910 I.WP = val;
911 }
912
TMS99XX_GET_REG(int regnum)913 unsigned TMS99XX_GET_REG(int regnum)
914 {
915 switch( regnum )
916 {
917 case TMS9900_PC: return I.PC;
918 case TMS9900_IR: return I.IR;
919 case TMS9900_WP: return I.WP;
920 case TMS9900_STATUS: return I.STATUS;
921 }
922 return 0;
923 }
924
TMS99XX_SET_REG(int regnum,unsigned val)925 void TMS99XX_SET_REG(int regnum, unsigned val)
926 {
927 switch( regnum )
928 {
929 case TMS9900_PC: I.PC = val; break;
930 case TMS9900_IR: I.IR = val; break;
931 case TMS9900_WP: I.WP = val; break;
932 case TMS9900_STATUS: I.STATUS = val; break;
933 }
934 }
935
936 #if (TMS99XX_MODEL == TMS9900_ID)
937
938 /*
939 void tms9900_set_nmi_line(int state) : change the state of the LOAD* line
940
941 state == 0 -> LOAD* goes high (inactive)
942 state != 0 -> LOAD* goes low (active)
943
944 While LOAD* is low, we keep triggering LOAD interrupts...
945
946 A problem : some peripheral lower the LOAD* line for a fixed time interval (causing the 1st
947 instruction of the LOAD interrupt routine to be repeated while the line is low), and will be
948 perfectly happy with the current scheme, but others might be more clever and wait for the IAQ
949 (Instruction acquisition) line to go high, and this needs a callback function to emulate.
950 */
tms9900_set_nmi_line(int state)951 void tms9900_set_nmi_line(int state)
952 {
953 I.load_state = state; /* save new state */
954
955 field_interrupt(); /* interrupt status changed */
956 }
957
958 /*
959 void tms9900_set_irq_line(int irqline, int state) : sets the state of the interrupt line.
960
961 irqline is ignored, and should always be 0.
962
963 state == 0 -> INTREQ* goes high (inactive)
964 state != 0 -> INTREQ* goes low (active)
965 */
966 /*
967 R Nabet 991020, revised 991218 :
968 In short : interrupt code should call "cpu_set_irq_line(0, 0, ASSERT_LINE);" to set an
969 interrupt request (level-triggered interrupts). Also, there MUST be a call to
970 "cpu_set_irq_line(0, 0, CLEAR_LINE);" in the machine code, when the interrupt line is released by
971 the hardware (generally in response to an action performed by the interrupt routines).
972 On tms9995 (9989 ?), you can use PULSE_LINE, too, since the processor latches the line...
973
974 **Note** : HOLD_LINE *NEVER* makes sense on the TMS9900 (or 9980, 9995...). The reason is the
975 TMS9900 does NOT tell the world it acknoledges an interrupt, so no matter how much hardware you
976 se, you cannot know when the CPU takes the interrupt, hence you cannot release the line when
977 the CPU takes the interrupt. Generally, the interrupt condition is cleared by the interrupt
978 routine (with some CRU or memory access).
979
980 Note that cpu_generate_interrupt uses HOLD_LINE, so your driver interrupt code
981 should always use the new style, i.e. return "ignore_interrupt()" and call
982 "cpu_set_irq_line(0, 0, ASSERT_LINE);" explicitely.
983
984 Last, many TMS9900-based hardware use a TMS9901 interrupt-handling chip. If anybody wants
985 to emulate some hardware which uses it, note that I am writing some emulation in the TI99/4(A)
986 driver in MESS, so you should ask me.
987 */
988 /*
989 * HJB 990430: changed to use irq_callback() to retrieve the vector
990 * instead of using 16 irqlines.
991 *
992 * R Nabet 990830 : My mistake, I rewrote all these once again ; I think it is now correct.
993 * A driver using the TMS9900 should do :
994 * cpu_0_irq_line_vector_w(0, level);
995 * cpu_set_irq_line(0,0,ASSERT_LINE);
996 *
997 * R Nabet 991108 : revised once again, with advice from Juergen Buchmueller, after a discussion
998 * with Nicola...
999 * We use the callback to retreive the interrupt level as soon as INTREQ* is asserted.
1000 * As a consequence, I do not support HOLD_LINE normally... However, we do not really have to
1001 * support HOLD_LINE, since no real world TMS9900-based system can support this.
1002 * FYI, there are two alternatives to retreiving the interrupt level with the callback :
1003 * a) using 16 pseudo-IRQ lines. Mostly OK, though it would require a few core changes.
1004 * However, this could cause some problems if someone tried to set two lines simulteanously...
1005 * And TMS9900 did NOT have 16 lines ! This is why Juergen and I did not retain this solution.
1006 * b) modifying the interrupt system in order to provide an extra int to every xxx_set_irq_line
1007 * function. I think this solution would be fine, but it would require quite a number of
1008 * changes in the MAME core. (And I did not feel the courage to check out 4000 drivers and 25
1009 * cpu cores ;-) .)
1010 *
1011 * Note that this does not apply to tms9995.
1012 */
tms9900_set_irq_line(int irqline,int state)1013 void tms9900_set_irq_line(int irqline, int state)
1014 {
1015 /*if (I.irq_state == state)
1016 return;*/
1017
1018 I.irq_state = state;
1019
1020 if (state == CLEAR_LINE)
1021 I.irq_level = 16;
1022 /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */
1023 else
1024 {
1025 #if SILLY_INTERRUPT_HACK
1026 I.irq_level = IRQ_MAGIC_LEVEL;
1027 #else
1028 I.irq_level = (* I.irq_callback)(0);
1029 #endif
1030 }
1031
1032 field_interrupt(); /* interrupt state is likely to have changed */
1033 }
1034
1035 #elif (TMS99XX_MODEL == TMS9980_ID)
1036 /*
1037 interrupt system similar to tms9900, but only 3 interrupt pins (IC0-IC2)
1038 */
1039
tms9980a_set_nmi_line(int state)1040 void tms9980a_set_nmi_line(int state)
1041 {
1042 /*no dedicated nmi line*/
1043 }
1044
tms9980a_set_irq_line(int irqline,int state)1045 void tms9980a_set_irq_line(int irqline, int state)
1046 {
1047 if (state == CLEAR_LINE)
1048 {
1049 I.load_state = 0;
1050 I.irq_state = 0;
1051 I.irq_level = 16;
1052 /* trick : 16 will always be bigger than the IM (0-15), so there will never be interrupts */
1053 }
1054 else
1055 {
1056 #if SILLY_INTERRUPT_HACK
1057 #error "OK, this does not work with tms9980a"
1058 /*I.load_state = 0;
1059 I.irq_state = 1;
1060 I.irq_level = IRQ_MAGIC_LEVEL;*/
1061 #else
1062 int level;
1063
1064 level = (* I.irq_callback)(0);
1065
1066 switch (level)
1067 {
1068 case 0:
1069 case 1:
1070 I.load_state = 0;
1071 I.irq_state = 0;
1072 I.irq_level = 16;
1073 tms9980a_reset(NULL);
1074 break;
1075 case 2:
1076 I.load_state = 1;
1077 I.irq_state = 0;
1078 I.irq_level = 16;
1079 break;
1080 case 7:
1081 I.load_state = 0;
1082 I.irq_state = 0;
1083 I.irq_level = 16;
1084 break;
1085 default: /* external levels 1, 2, 3, 4 */
1086 I.load_state = 0;
1087 I.irq_state = 1;
1088 I.irq_level = level - 2;
1089 break;
1090 }
1091 #endif
1092 }
1093
1094 field_interrupt(); /* interrupt state is likely to have changed */
1095 }
1096
1097 #elif (TMS99XX_MODEL == TMS9995_ID)
1098 /*
1099 we latch interrupts when they make an inactive to active transition
1100 */
1101
tms9995_set_nmi_line(int state)1102 void tms9995_set_nmi_line(int state)
1103 {
1104 I.load_state = state; /* save new state */
1105
1106 field_interrupt(); /* interrupt status changed */
1107 }
1108
1109
1110 /*
1111 this call-back is called by MESS timer system when the timer reaches 0.
1112 */
decrementer_callback(int ignored)1113 static void decrementer_callback(int ignored)
1114 {
1115 /* request decrementer interrupt */
1116 I.int_latch |= 0x8;
1117 I.flag |= 0x8;
1118
1119 field_interrupt();
1120 }
1121
1122
1123 /*
1124 reset and load the timer/decrementer
1125
1126 Note that I don't know whether toggling flag0/flag1 causes the decrementer to be reloaded or not
1127 */
reset_decrementer(void)1128 static void reset_decrementer(void)
1129 {
1130 if (I.timer)
1131 {
1132 timer_remove(I.timer);
1133 I.timer = NULL;
1134 }
1135
1136 /* decrementer / timer enabled ? */
1137 I.decrementer_enabled = ((I.flag & 2) && (I.decrementer_interval));
1138
1139 if (I.decrementer_enabled)
1140 {
1141 if (I.flag & 1)
1142 { /* decrementer */
1143 I.decrementer_count = I.decrementer_interval;
1144 }
1145 else
1146 { /* timer */
1147 I.timer = timer_pulse(TIME_IN_CYCLES(I.decrementer_interval * 16L, cpu_getactivecpu()),
1148 0, decrementer_callback);
1149 }
1150 }
1151 }
1152
1153 /*
1154 You have two interrupt line : one triggers level-1 interrupts, the other triggers level-4
1155 interrupts (or decrements the decrementer register).
1156
1157 According to the hardware, you may use PULSE_LINE (edge-triggered interrupts), or ASSERT_LINE
1158 (level-triggered interrupts). Edge-triggered interrupts are way simpler, but if multiple devices
1159 share the same line, they must use level-triggered interrupts.
1160 */
tms9995_set_irq_line(int irqline,int state)1161 void tms9995_set_irq_line(int irqline, int state)
1162 {
1163 int mask = (irqline == 0) ? 0x2 : 0x10;
1164 int flag_mask = (irqline == 0) ? 0x4 : 0x10;
1165
1166 if (((I.int_state & mask) != 0) ^ (state != 0))
1167 { /* only if state changes */
1168 if (state)
1169 {
1170 I.int_state |= mask;
1171
1172 if ((irqline == 1) && (I.flag & 1))
1173 { /* event counter mode : INT4* triggers no interrupt... */
1174 if (I.decrementer_enabled)
1175 { /* decrement, then interrupt if reach 0 */
1176 if ((-- I.decrementer_count) == 0)
1177 {
1178 decrementer_callback(0);
1179 I.decrementer_count = I.decrementer_interval; /* reload */
1180 }
1181 }
1182 }
1183 else
1184 { /* plain interrupt mode */
1185 I.int_latch |= mask;
1186 I.flag |= flag_mask;
1187 }
1188 }
1189 else
1190 {
1191 I.int_state &= ~ mask;
1192 }
1193
1194 field_interrupt(); /* interrupt status changed */
1195 }
1196 }
1197
1198 #else
1199
1200 #error "interrupt system not implemented"
1201
1202 #endif
1203
TMS99XX_SET_IRQ_CALLBACK(int (* callback)(int irqline))1204 void TMS99XX_SET_IRQ_CALLBACK(int (*callback)(int irqline))
1205 {
1206 I.irq_callback = callback;
1207 }
1208
1209 /*
1210 * field_interrupt
1211 *
1212 * Determines whether if an interrupt is pending, and sets the revelant flag.
1213 *
1214 * Called when an interrupt pin (LOAD*, INTREQ*, IC0-IC3) is changed, and when the interrupt mask
1215 * is modified.
1216 *
1217 * By using this flag, we save some compares in the execution loop. Subtle, isn't it ;-) ?
1218 *
1219 * R Nabet.
1220 */
1221 #if (TMS99XX_MODEL == TMS9900_ID) || (TMS99XX_MODEL == TMS9980_ID)
1222
field_interrupt(void)1223 static void field_interrupt(void)
1224 {
1225 I.interrupt_pending = ((I.irq_level <= IMASK) || (I.load_state));
1226 }
1227
1228 #elif (TMS99XX_MODEL == TMS9995_ID)
1229
field_interrupt(void)1230 static void field_interrupt(void)
1231 {
1232 if (I.load_state)
1233 {
1234 I.interrupt_pending = 1;
1235 }
1236 else
1237 {
1238 int current_int;
1239 int level;
1240
1241 if (I.flag & 1)
1242 /* event counter mode : ignore int4* line... */
1243 current_int = (I.int_state & ~0x10) | I.int_latch;
1244 else
1245 /* normal behavior */
1246 current_int = I.int_state | I.int_latch;
1247
1248 if (current_int)
1249 /* find first bit to 1 */
1250 /* possible values : 1, 3, 4 */
1251 for (level=0; ! (current_int & 1); current_int >>= 1, level++)
1252 ;
1253 else
1254 level=16;
1255
1256 I.irq_level = level;
1257
1258 I.interrupt_pending = (level <= IMASK);
1259 }
1260 }
1261
1262 #else
1263
1264 #error "field_interrupt() not written"
1265
1266 #endif
1267
1268 /****************************************************************************
1269 * Return a formatted string for a register
1270 ****************************************************************************/
TMS99XX_INFO(void * context,int regnum)1271 const char *TMS99XX_INFO(void *context, int regnum)
1272 {
1273 switch( regnum )
1274 {
1275 case CPU_INFO_NAME: return TMS99XX_CPU_NAME;
1276 case CPU_INFO_FAMILY: return "Texas Instruments 9900";
1277 case CPU_INFO_VERSION: return "2.0";
1278 case CPU_INFO_FILE: return __FILE__;
1279 case CPU_INFO_CREDITS: return "C TMS9900 emulator by Edward Swartz, initially converted for Mame by M.Coates, updated by R. Nabet";
1280 }
1281 return "";
1282 }
1283
TMS99XX_DASM(char * buffer,unsigned pc)1284 unsigned TMS99XX_DASM(char *buffer, unsigned pc)
1285 {
1286 sprintf( buffer, "$%04X", readword(pc) );
1287 return 2;
1288 }
1289
1290 /**************************************************************************/
1291
1292 #if (TMS99XX_MODEL == TMS9995_ID)
1293
1294 /* set decrementer mode flag */
set_flag0(int val)1295 static void set_flag0(int val)
1296 {
1297 if (val)
1298 I.flag |= 1;
1299 else
1300 I.flag &= ~ 1;
1301
1302 reset_decrementer();
1303 }
1304
1305 /* set decrementer enable flag */
set_flag1(int val)1306 static void set_flag1(int val)
1307 {
1308 if (val)
1309 I.flag |= 2;
1310 else
1311 I.flag &= ~ 2;
1312
1313 reset_decrementer();
1314 }
1315
1316 #endif
1317
1318 /*
1319 performs a normal write to CRU bus (used by SBZ, SBO, LDCR : address range 0 -> 0xFFF)
1320 */
writeCRU(int CRUAddr,int Number,UINT16 Value)1321 static void writeCRU(int CRUAddr, int Number, UINT16 Value)
1322 {
1323 #if (TMS99XX_MODEL == TMS9900_ID)
1324 /* 3 MSBs are always 0 to support external instructions */
1325 #define wCRUAddrMask 0xFFF;
1326 #elif (TMS99XX_MODEL == TMS9980_ID)
1327 /* 2 bits unused, and 2 MSBs are always 0 to support external instructions */
1328 #define wCRUAddrMask 0x7FF;
1329 #elif (TMS99XX_MODEL == TMS9995_ID)
1330 /* no such problem here : data bus lines D0-D2 provide the external instruction code */
1331 #define wCRUAddrMask 0x7FFF;
1332 #else
1333 #warning "I don't know how your processor handle CRU."
1334 #define wCRUAddrMask 0x7FFF;
1335 #endif
1336
1337 int count;
1338
1339 //logerror("PC %4.4x Write CRU %x for %x =%x\n",I.PC,CRUAddr,Number,Value);
1340
1341 CRUAddr &= wCRUAddrMask;
1342
1343 /* Write Number bits from CRUAddr */
1344
1345 for(count=0; count<Number; count++)
1346 {
1347 #if (TMS99XX_MODEL == TMS9995_ID)
1348 if (CRUAddr == 0xF70)
1349 set_flag0(Value & 0x01);
1350 else if (CRUAddr == 0xF71)
1351 set_flag1(Value & 0x01);
1352 else if ((CRUAddr >= 0xF72) && (CRUAddr < 0xF75))
1353 ; /* ignored */
1354 else if ((CRUAddr >= 0xF75) && (CRUAddr < 0xF80))
1355 { /* user defined flags */
1356 int mask = 1 << (CRUAddr - 0xF70);
1357 if (Value & 0x01)
1358 I.flag |= mask;
1359 else
1360 I.flag &= ~ mask;
1361 }
1362 else if (CRUAddr == 0x0FED)
1363 /* MID flag */
1364 I.MID_flag = Value & 0x01;
1365 else
1366 /* External CRU */
1367 #endif
1368 cpu_writeport(CRUAddr, (Value & 0x01));
1369 Value >>= 1;
1370 CRUAddr = (CRUAddr + 1) & wCRUAddrMask;
1371 }
1372 }
1373
1374 /*
1375 Some opcodes perform a dummy write to a special CRU address, so that an external function may be
1376 triggered.
1377
1378 Only the first 3 MSBs of the address matter : other address bits and the written value itself
1379 are undefined.
1380
1381 How should we support this ? With callback functions ? Actually, as long as we do not support
1382 hardware which makes use of this feature, it does not really matter :-) .
1383 */
external_instruction_notify(int ext_op_ID)1384 static void external_instruction_notify(int ext_op_ID)
1385 {
1386 #if 1
1387 /* I guess we can support this like normal CRU operations */
1388 #if (TMS99XX_MODEL == TMS9900_ID)
1389 cpu_writeport(ext_op_ID << 12, 0); /* or is it 1 ??? */
1390 #elif (TMS99XX_MODEL == TMS9980_ID)
1391 cpu_writeport((ext_op_ID & 3) << 11, (ext_op_ID & 4) ? 1 : 0);
1392 #elif (TMS99XX_MODEL == TMS9995_ID)
1393 cpu_writeport(ext_op_ID << 15, 0); /* or is it 1 ??? */
1394 #else
1395 #warning "I don't know how your processor handle external opcodes (maybe you don't need them, though)."
1396 #endif
1397
1398 #else
1399 switch (ext_op_ID)
1400 {
1401 case 2: /* IDLE */
1402
1403 break;
1404 case 3: /* RSET */
1405
1406 break;
1407 case 5: /* CKON */
1408
1409 break;
1410 case 6: /* CKOF */
1411
1412 break;
1413 case 7: /* LREX */
1414
1415 break;
1416 case 0:
1417 /* normal CRU write !!! */
1418 //logerror("PC %4.4x : external_instruction_notify : wrong ext_op_ID",I.PC);
1419 break;
1420 default:
1421 /* unknown address */
1422 //logerror("PC %4.4x : external_instruction_notify : unknown ext_op_ID",I.PC);
1423 break;
1424 }
1425 #endif
1426 }
1427
1428 /*
1429 performs a normal read to CRU bus (used by TB, STCR : address range 0->0xFFF)
1430
1431 Note that on some hardware, e.g. TI99, all normal memory operations cause unwanted CRU
1432 read at the same address.
1433 This seems to be impossible to emulate efficiently.
1434 */
1435 #if (TMS99XX_MODEL != TMS9995_ID)
1436 #define READPORT(Port) cpu_readport(Port)
1437 #else
1438 /* on tms9995, we have to handle internal CRU port */
READPORT(int Port)1439 int READPORT(int Port)
1440 {
1441 if (Port == 0x1EE)
1442 /* flag, bits 0-7 */
1443 return I.flag & 0xFF;
1444 else if (Port == 0x1EF)
1445 /* flag, bits 8-15 */
1446 return (I.flag >> 8) & 0xFF;
1447 else if (Port == 0x1FD)
1448 /* MID flag, and extrernal devices */
1449 if (I.MID_flag)
1450 return cpu_readport(Port) | 0x10;
1451 else
1452 return cpu_readport(Port) & ~ 0x10;
1453 else
1454 /* extrernal devices */
1455 return cpu_readport(Port);
1456 }
1457 #endif
1458
readCRU(int CRUAddr,int Number)1459 static UINT16 readCRU(int CRUAddr, int Number)
1460 {
1461 #if (TMS99XX_MODEL == TMS9900_ID)
1462 /* 3 MSBs are always 0 to support external instructions */
1463 #define rCRUAddrMask 0x1FF
1464 #elif (TMS99XX_MODEL == TMS9980_ID)
1465 /* 2 bits unused, and 2 MSBs are always 0 to support external instructions */
1466 #define rCRUAddrMask 0x0FF
1467 #elif (TMS99XX_MODEL == TMS9995_ID)
1468 /* no such problem here : data bus lines D0-D2 provide the external instruction code */
1469 #define rCRUAddrMask 0xFFF
1470 #else
1471 #warning "I don't know how your processor handle CRU."
1472 #define rCRUAddrMask 0xFFF
1473 #endif
1474
1475 static int BitMask[] =
1476 {
1477 0, /* filler - saves a subtract to find mask */
1478 0x0100,0x0300,0x0700,0x0F00,0x1F00,0x3F00,0x7F00,0xFF00,
1479 0x01FF,0x03FF,0x07FF,0x0FFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF
1480 };
1481
1482 int Offset,Location,Value;
1483
1484 //logerror("Read CRU %x for %x\n",CRUAddr,Number);
1485
1486 Location = CRUAddr >> 3;
1487 Offset = CRUAddr & 07;
1488
1489 if (Number <= 8)
1490 {
1491 /* Read 16 Bits */
1492 Value = (READPORT((Location + 1) & rCRUAddrMask) << 8)
1493 | READPORT(Location & rCRUAddrMask);
1494
1495 /* Allow for Offset */
1496 Value >>= Offset;
1497
1498 /* Mask out what we want */
1499 Value = (Value << 8) & BitMask[Number];
1500
1501 /* And update */
1502 return (Value>>8);
1503 }
1504 else
1505 {
1506 /* Read 24 Bits */
1507 Value = (READPORT((Location + 2) & rCRUAddrMask) << 16)
1508 | (READPORT((Location + 1) & rCRUAddrMask) << 8)
1509 | READPORT(Location & rCRUAddrMask);
1510
1511 /* Allow for Offset */
1512 Value >>= Offset;
1513
1514 /* Mask out what we want */
1515 Value &= BitMask[Number];
1516
1517 /* and Update */
1518 return Value;
1519 }
1520 }
1521
1522 /**************************************************************************/
1523
1524 /* fetch : read one word at * PC, and increment PC. */
1525
fetch(void)1526 static UINT16 fetch(void)
1527 {
1528 register UINT16 value = readword(I.PC);
1529 I.PC += 2;
1530 return value;
1531 }
1532
1533 /* contextswitch : performs a BLWP, ie change PC, WP, and save PC, WP and ST... */
contextswitch(UINT16 addr)1534 static void contextswitch(UINT16 addr)
1535 {
1536 UINT16 oldWP, oldpc;
1537
1538 /* save old state */
1539 oldWP = I.WP;
1540 oldpc = I.PC;
1541
1542 /* load vector */
1543 I.WP = readword(addr) & ~1;
1544 I.PC = readword(addr+2) & ~1;
1545
1546 /* write old state to regs */
1547 WRITEREG(R13, oldWP);
1548 WRITEREG(R14, oldpc);
1549 setstat();
1550 WRITEREG(R15, I.STATUS);
1551 }
1552
1553 /*
1554 * decipheraddr : compute and return the effective adress in word instructions.
1555 *
1556 * NOTA : the LSB is always ignored in word adresses,
1557 * but we do not set to 0 because of XOP...
1558 */
decipheraddr(UINT16 opcode)1559 static UINT16 decipheraddr(UINT16 opcode)
1560 {
1561 register UINT16 ts = opcode & 0x30;
1562 register UINT16 reg = opcode & 0xF;
1563
1564 reg += reg;
1565
1566 if (ts == 0)
1567 /* Rx */
1568 return(reg + I.WP);
1569 else if (ts == 0x10)
1570 { /* *Rx */
1571 CYCLES(4, 1);
1572 return(readword(reg + I.WP));
1573 }
1574 else if (ts == 0x20)
1575 {
1576 register UINT16 imm;
1577
1578 imm = fetch();
1579
1580 if (reg)
1581 { /* @>xxxx(Rx) */
1582 CYCLES(8, 3);
1583 return(readword(reg + I.WP) + imm);
1584 }
1585 else
1586 { /* @>xxxx */
1587 CYCLES(8, 1);
1588 return(imm);
1589 }
1590 }
1591 else /*if (ts == 0x30)*/
1592 { /* *Rx+ */
1593 register UINT16 response;
1594
1595 reg += I.WP; /* reg now contains effective address */
1596
1597 CYCLES(8, 3);
1598
1599 response = readword(reg);
1600 writeword(reg, response+2); /* we increment register content */
1601 return(response);
1602 }
1603 }
1604
1605 /* decipheraddrbyte : compute and return the effective adress in byte instructions. */
decipheraddrbyte(UINT16 opcode)1606 static UINT16 decipheraddrbyte(UINT16 opcode)
1607 {
1608 register UINT16 ts = opcode & 0x30;
1609 register UINT16 reg = opcode & 0xF;
1610
1611 reg += reg;
1612
1613 if (ts == 0)
1614 /* Rx */
1615 return(reg + I.WP);
1616 else if (ts == 0x10)
1617 { /* *Rx */
1618 CYCLES(4, 1);
1619 return(readword(reg + I.WP));
1620 }
1621 else if (ts == 0x20)
1622 {
1623 register UINT16 imm;
1624
1625 imm = fetch();
1626
1627 if (reg)
1628 { /* @>xxxx(Rx) */
1629 CYCLES(8, 3);
1630 return(readword(reg + I.WP) + imm);
1631 }
1632 else
1633 { /* @>xxxx */
1634 CYCLES(8, 1);
1635 return(imm);
1636 }
1637 }
1638 else /*if (ts == 0x30)*/
1639 { /* *Rx+ */
1640 register UINT16 response;
1641
1642 reg += I.WP; /* reg now contains effective address */
1643
1644 CYCLES(6, 3);
1645
1646 response = readword(reg);
1647 writeword(reg, response+1); /* we increment register content */
1648 return(response);
1649 }
1650 }
1651
1652
1653 /*************************************************************************/
1654
1655 #if TMS99XX_MODEL <= TMS9989_ID
1656 /* TMS9900/TMS9980 merely ignore the instruction */
1657 #define HANDLE_ILLEGAL TMS99XX_ICOUNT -= 6
1658 #elif TMS99XX_MODEL == TMS9995_ID
1659 /* TMS9995 generates a MID interrupt */
1660 #define HANDLE_ILLEGAL \
1661 { \
1662 I.MID_flag = 1; \
1663 contextswitch(0x0008); \
1664 I.STATUS = (I.STATUS & 0xFE00) | 0x1; \
1665 disable_interrupt_recognition = 1; \
1666 }
1667 #else
1668 #define HANDLE_ILLEGAL
1669 #warning "don't know"
1670 #endif
1671
1672 /*==========================================================================
1673 Illegal instructions >0000->01FF (not for 9989 and later)
1674 >0C00->0FFF (not for 99xxx)
1675 ============================================================================*/
1676
illegal(UINT16 opcode)1677 static void illegal(UINT16 opcode)
1678 {
1679 HANDLE_ILLEGAL;
1680 }
1681
1682
1683 #if (TMS99XX_MODEL >= TMS99105A_ID)
1684 /*==========================================================================
1685 Additionnal instructions, >0000->002F
1686 Additionnal single-register instruction, >0030->003F
1687 ---------------------------------------------------------------------------
1688
1689 0 1 2 3-4 5 6 7+8 9 A B-C D E F
1690 ---------------------------------
1691 | o p c o d e |
1692 | o p c o d e | reg # |
1693 ---------------------------------
1694
1695 tms99xxx : SRAM, SLAM, AM, SM
1696 ============================================================================*/
h0000(UINT16 opcode)1697 static void h0000(UINT16 opcode)
1698 {
1699 #if 0
1700 if (opcode & 0x30)
1701 { /* STPC STore Program Counter */
1702
1703 }
1704 else
1705 #endif
1706
1707 switch (opcode /*& 0x3F*/)
1708 {
1709 case 0x1C: /* SRAM */
1710 /* SRAM -- Shift Right Arithmetic Multiple */
1711 /* right shift on a 32-bit operand */
1712 /* ... */
1713 break;
1714 case 0x1D: /* SLAM */
1715 /* SLAM -- Shift Left Arithmetic Multiple */
1716 /* left shift on a 32-bit operand */
1717 /* ... */
1718 break;
1719
1720 case 0x29: /* AM (or SM ?) */
1721 /* AM ---- Add Multiple */
1722 /* add with 32-bit operands */
1723 /* ... */
1724 break;
1725 case 0x2A: /* SM (or AM ?) */
1726 /* SM ---- Subtract Multiple */
1727 /* substract with 32-bit operands */
1728 /* ... */
1729 break;
1730
1731 #if 0
1732 case 0x1E:
1733 /* RTO --- Right Test for One */
1734 case 0x1F:
1735 /* LTO --- Left Test for One */
1736 case 0x20:
1737 /* CNTO -- CouNT Ones */
1738 case 0x21:
1739 /* SLSL -- Search LiSt Logical address */
1740 case 0x22:
1741 /* SLSP -- Search LiSt Physical address */
1742 case 0x23:
1743 /* BDC --- Binary to Decimal ascii Conversion */
1744 case 0x24:
1745 /* DBC --- Decimal ascii to Binary Conversion */
1746 case 0x25:
1747 /* SWPM -- SWaP Multiple precision */
1748 case 0x26:
1749 /* XORM -- eXclusive OR Multiple precision */
1750 case 0x27:
1751 /* ORM --- OR Multiple precision */
1752 case 0x28:
1753 /* ANDM -- AND Multiple precision */
1754
1755 case 0x2B:
1756 /* MOVA -- MOVe Address */
1757 case 0x2D:
1758 /* EMD --- Execute Micro-Diagnostics */
1759 case 0x2E:
1760 /* EINT -- Enable INTerrupts */
1761 case 0x2F:
1762 /* DINT -- Disable INTerrupts */
1763
1764 break;
1765 #endif
1766
1767 default:
1768 HANDLE_ILLEGAL;
1769 break;
1770 }
1771 }
1772 #endif
1773
1774
1775 #if (TMS99XX_MODEL >= TMS9989_ID)
1776 /*==========================================================================
1777 Additionnal single-register instructions, >0040->00FF
1778 ---------------------------------------------------------------------------
1779
1780 0 1 2 3-4 5 6 7+8 9 A B-C D E F
1781 ---------------------------------
1782 | o p c o d e | reg # |
1783 ---------------------------------
1784
1785 tms9989 and later : LST, LWP
1786 tms99xxx : BLSK
1787 ============================================================================*/
h0040(UINT16 opcode)1788 static void h0040(UINT16 opcode)
1789 {
1790 register UINT16 addr;
1791
1792 addr = opcode & 0xF;
1793 addr = ((addr + addr) + I.WP) & ~1;
1794
1795 switch ((opcode & 0xF0) >> 4)
1796 {
1797 case 8: /* LST */
1798 /* LST --- Load STatus register */
1799 /* ST = *Reg */
1800 I.STATUS = readword(addr);
1801 break;
1802 case 9: /* LWP */
1803 /* LWP --- Load Workspace Pointer register */
1804 /* WP = *Reg */
1805 I.WP = readword(addr);
1806 break;
1807
1808 #if (TMS99XX_MODEL >= TMS99105A_ID)
1809 case 11: /* BLSK */
1810 /* BLSK -- Branch immediate & Link to StacK */
1811
1812 break;
1813 #endif
1814
1815 #if 0
1816 case 4:
1817 /* CS ---- Compare Strings */
1818 case 5:
1819 /* SEQB -- Search string for EQual Byte */
1820 case 6:
1821 /* MOVS -- MOVe String */
1822 case 7:
1823 /* LIM --- Load Interrupt Mask */
1824
1825 case 10:
1826 /* LCS --- Load writable Control Store */
1827
1828 case 12:
1829 /* MVSR -- MoVe String Reverse */
1830 case 13:
1831 /* MVSK -- MoVe String from stacK */
1832 case 14:
1833 /* POPS -- POP String from stack */
1834 case 15:
1835 /* PSHS -- PuSH String to stack */
1836
1837 break;
1838 #endif
1839
1840 default:
1841 HANDLE_ILLEGAL;
1842 break;
1843 }
1844 }
1845
1846
1847 /*==========================================================================
1848 Additionnal single-operand instructions, >0100->01FF
1849 ---------------------------------------------------------------------------
1850
1851 0 1 2 3-4 5 6 7+8 9 A B-C D E F
1852 ---------------------------------
1853 | o p c o d e |TS | S |
1854 ---------------------------------
1855
1856 tms9989 and later : DIVS, MPYS
1857 tms99xxx : BIND
1858 ============================================================================*/
h0100(UINT16 opcode)1859 static void h0100(UINT16 opcode)
1860 {
1861 register UINT16 src;
1862
1863 src = decipheraddr(opcode) & ~1;
1864
1865 switch ((opcode & 0xC0) >> 6)
1866 {
1867 #if (TMS99XX_MODEL >= TMS99105A_ID)
1868 case 1:
1869 /* BIND -- Branch INDirect */
1870
1871 break;
1872 #endif
1873
1874 case 2: /* DIVS */
1875 /* DIVS -- DIVide Signed */
1876 /* R0 = (R0:R1)/S R1 = (R0:R1)%S */
1877 {
1878 INT16 d = readword(src);
1879 long divq = (READREG(R0) << 16) | READREG(R1);
1880 long q = divq/d;
1881
1882 if ((q < -32768L) || (q > 32767L))
1883 {
1884 I.STATUS |= ST_OV;
1885 CYCLES(24 /*don't know*/, 10);
1886 }
1887 else
1888 {
1889 I.STATUS &= ~ST_OV;
1890 setst_lae(q);
1891 WRITEREG(R0, q);
1892 WRITEREG(R1, divq%d);
1893 /* tms9995 : 33 is the worst case */
1894 CYCLES(102 /*don't know*/, 33);
1895 }
1896 }
1897 break;
1898
1899 case 3: /* MPYS */
1900 /* MPYS -- MultiPlY Signed */
1901 /* Results: R0:R1 = R0*S */
1902 {
1903 long prod = ((long) (INT16) READREG(R0)) * ((long) (INT16) readword(src));
1904
1905 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
1906 if (prod > 0)
1907 I.STATUS |= (ST_LGT | ST_AGT);
1908 else if (prod < 0)
1909 I.STATUS |= ST_LGT;
1910 else
1911 I.STATUS |= ST_EQ;
1912
1913 WRITEREG(R0, prod >> 16);
1914 WRITEREG(R1, prod);
1915 }
1916 CYCLES(56 /*don't know*/, 25);
1917 break;
1918
1919 #if 0
1920 case 0:
1921 /* EVAD -- EValuate ADdress instruction */
1922
1923 break;
1924 #endif
1925
1926 default:
1927 HANDLE_ILLEGAL;
1928 break;
1929 }
1930 }
1931 #endif
1932
1933
1934 /*==========================================================================
1935 Immediate, Control instructions, >0200->03FF
1936 ---------------------------------------------------------------------------
1937
1938 0 1 2 3-4 5 6 7+8 9 A B-C D E F
1939 ---------------------------------
1940 | o p c o d e |0| reg # |
1941 ---------------------------------
1942
1943 LI, AI, ANDI, ORI, CI, STWP, STST, LIMI, LWPI, IDLE, RSET, RTWP, CKON, CKOF, LREX
1944 ============================================================================*/
h0200(UINT16 opcode)1945 static void h0200(UINT16 opcode)
1946 {
1947 register UINT16 addr;
1948 register UINT16 value; /* used for anything */
1949
1950 addr = opcode & 0xF;
1951 addr = ((addr + addr) + I.WP) & ~1;
1952
1953 #if 0
1954 if ((opcode >= 0x0320) && (opcode < 0x0340))
1955 { /* LMF */
1956 /* LMF --- Load memory Map File */
1957 /* I don't know what it does exactly. I guess it was used by some paging system on some
1958 TI990/10 variant.
1959 Syntax : LMF Rx,x; where Rx can be any workspace register from 0 thru 15, and x can be
1960 a `0' or a `1'. */
1961 /* ... */
1962 return;
1963 }
1964 #endif
1965
1966 #if (TMS99XX_MODEL >= TMS9995_ID)
1967 /* better instruction decoding on tms9995 */
1968 if (((opcode < 0x2E0) && (opcode & 0x10)) || ((opcode >= 0x2E0) && (opcode & 0x1F)))
1969 {
1970 #if 0
1971 if (opcode == 0x0301)
1972 { /* CR ---- Compare Reals */
1973 }
1974 else if (opcode == 0x0301)
1975 { /* MM ---- Multiply Multiple */
1976 }
1977 else if (opcode >= 0x03F0)
1978 { /* EP ---- Extend Precision */
1979 }
1980 else
1981 #endif
1982 HANDLE_ILLEGAL;
1983 return;
1984 }
1985 #endif
1986
1987 switch ((opcode & 0x1e0) >> 5)
1988 {
1989 case 0: /* LI */
1990 /* LI ---- Load Immediate */
1991 /* *Reg = *PC+ */
1992 value = fetch();
1993 writeword(addr, value);
1994 setst_lae(value);
1995 CYCLES(12, 3);
1996 break;
1997 case 1: /* AI */
1998 /* AI ---- Add Immediate */
1999 /* *Reg += *PC+ */
2000 value = fetch();
2001 wadd(addr, value);
2002 CYCLES(14, 4);
2003 break;
2004 case 2: /* ANDI */
2005 /* ANDI -- AND Immediate */
2006 /* *Reg &= *PC+ */
2007 value = fetch();
2008 value = readword(addr) & value;
2009 writeword(addr, value);
2010 setst_lae(value);
2011 CYCLES(14, 4);
2012 break;
2013 case 3: /* ORI */
2014 /* ORI --- OR Immediate */
2015 /* *Reg |= *PC+ */
2016 value = fetch();
2017 value = readword(addr) | value;
2018 writeword(addr, value);
2019 setst_lae(value);
2020 CYCLES(14, 4);
2021 break;
2022 case 4: /* CI */
2023 /* CI ---- Compare Immediate */
2024 /* status = (*Reg-*PC+) */
2025 value = fetch();
2026 setst_c_lae(value, readword(addr));
2027 CYCLES(14, 4);
2028 break;
2029 case 5: /* STWP */
2030 /* STWP -- STore Workspace Pointer */
2031 /* *Reg = WP */
2032 writeword(addr, I.WP);
2033 CYCLES(8, 3);
2034 break;
2035 case 6: /* STST */
2036 /* STST -- STore STatus register */
2037 /* *Reg = ST */
2038 setstat();
2039 writeword(addr, I.STATUS);
2040 CYCLES(8, 3);
2041 break;
2042 case 7: /* LWPI */
2043 /* LWPI -- Load Workspace Pointer Immediate */
2044 /* WP = *PC+ */
2045 I.WP = fetch();
2046 CYCLES(10, 4);
2047 break;
2048 case 8: /* LIMI */
2049 /* LIMI -- Load Interrupt Mask Immediate */
2050 /* ST&15 |= (*PC+)&15 */
2051 value = fetch();
2052 #if (TMS99XX_MODEL == TMS9940_ID)
2053 /* Interrupt mask is only two-bit-long on tms9940 */
2054 I.STATUS = (I.STATUS & ~ 0x3) | (value & 0x3);
2055 #else
2056 I.STATUS = (I.STATUS & ~ 0xF) | (value & 0xF);
2057 #endif
2058 field_interrupt(); /*IM has been modified.*/
2059 CYCLES(16, 5);
2060 break;
2061 case 9: /* LMF is implemented elsewhere - when it is implemented */
2062 HANDLE_ILLEGAL;
2063 break;
2064 case 10: /* IDLE */
2065 /* IDLE -- IDLE until a reset, interrupt, load */
2066 /* The TMS99000 locks until an interrupt happen (like with 68k STOP instruction),
2067 and continuously performs a special CRU write (code 2). */
2068 I.IDLE = 1;
2069 external_instruction_notify(2);
2070 CYCLES(12, 7);
2071 /* we take care of further external_instruction_notify(2); in execute() */
2072 break;
2073 case 11: /* RSET */
2074 /* RSET -- ReSET */
2075 /* Reset the Interrupt Mask, and perform a special CRU write (code 3). */
2076 /* Does not actually cause a reset, but an external circuitery could trigger one. */
2077 I.STATUS &= 0xFFF0; /*clear IM.*/
2078 field_interrupt(); /*IM has been modified.*/
2079 external_instruction_notify(3);
2080 CYCLES(12, 7);
2081 break;
2082 case 12: /* RTWP */
2083 /* RTWP -- Return with Workspace Pointer */
2084 /* WP = R13, PC = R14, ST = R15 */
2085 I.STATUS = READREG(R15);
2086 getstat(); /* set last_parity */
2087 I.PC = READREG(R14);
2088 I.WP = READREG(R13);
2089 field_interrupt(); /*IM has been modified.*/
2090 CYCLES(14, 6);
2091 break;
2092 case 13: /* CKON */
2093 case 14: /* CKOF */
2094 case 15: /* LREX */
2095 /* CKON -- ClocK ON */
2096 /* Perform a special CRU write (code 5). */
2097 /* An external circuitery could, for instance, enable a "decrement-and-interrupt" timer. */
2098 /* CKOF -- ClocK OFf */
2099 /* Perform a special CRU write (code 6). */
2100 /* An external circuitery could, for instance, disable a "decrement-and-interrupt" timer. */
2101 /* LREX -- Load or REstart eXecution */
2102 /* Perform a special CRU write (code 7). */
2103 /* An external circuitery could, for instance, activate the LOAD* line,
2104 causing a non-maskable LOAD interrupt (vector -1). */
2105 external_instruction_notify((opcode & 0x00e0) >> 5);
2106 CYCLES(12, 7);
2107 break;
2108 }
2109 }
2110
2111
2112 /*==========================================================================
2113 Single-operand instructions, >0400->07FF
2114 ---------------------------------------------------------------------------
2115
2116 0 1 2 3-4 5 6 7+8 9 A B-C D E F
2117 ---------------------------------
2118 | o p c o d e |TS | S |
2119 ---------------------------------
2120
2121 BLWP, B, X, CLR, NEG, INV, INC, INCT, DEC, DECT, BL, SWPB, SETO, ABS
2122 tms99xxx : LDD, LDS
2123 ============================================================================*/
h0400(UINT16 opcode)2124 static void h0400(UINT16 opcode)
2125 {
2126 register UINT16 addr = decipheraddr(opcode) & ~1;
2127 register UINT16 value; /* used for anything */
2128
2129 switch ((opcode & 0x3C0) >> 6)
2130 {
2131 case 0: /* BLWP */
2132 /* BLWP -- Branch and Link with Workspace Pointer */
2133 /* Result: WP = *S+, PC = *S */
2134 /* New R13=old WP, New R14=Old PC, New R15=Old ST */
2135 contextswitch(addr);
2136 CYCLES(26, 11);
2137 disable_interrupt_recognition = 1;
2138 break;
2139 case 1: /* B */
2140 /* B ----- Branch */
2141 /* PC = S */
2142 I.PC = addr;
2143 CYCLES(8, 3);
2144 break;
2145 case 2: /* X */
2146 /* X ----- eXecute */
2147 /* Executes instruction *S */
2148 execute(readword(addr));
2149 /* On tms9900, the X instruction actually takes 8 cycles, but we gain 4 cycles on the next
2150 instruction, as we don't need to fetch it. */
2151 CYCLES(4, 2);
2152 break;
2153 case 3: /* CLR */
2154 /* CLR --- CLeaR */
2155 /* *S = 0 */
2156 writeword(addr, 0);
2157 CYCLES(10, 3);
2158 break;
2159 case 4: /* NEG */
2160 /* NEG --- NEGate */
2161 /* *S = -*S */
2162 value = - (INT16) readword(addr);
2163 if (value)
2164 I.STATUS &= ~ ST_C;
2165 else
2166 I.STATUS |= ST_C;
2167 #if (TMS99XX_MODEL == TMS9940_ID)
2168 if (value & 0x0FFF)
2169 I.STATUS &= ~ ST_DC;
2170 else
2171 I.STATUS |= ST_DC;
2172 #endif
2173 setst_laeo(value);
2174 writeword(addr, value);
2175 CYCLES(12, 3);
2176 break;
2177 case 5: /* INV */
2178 /* INV --- INVert */
2179 /* *S = ~*S */
2180 value = ~ readword(addr);
2181 writeword(addr, value);
2182 setst_lae(value);
2183 CYCLES(10, 3);
2184 break;
2185 case 6: /* INC */
2186 /* INC --- INCrement */
2187 /* (*S)++ */
2188 wadd(addr, 1);
2189 CYCLES(10, 3);
2190 break;
2191 case 7: /* INCT */
2192 /* INCT -- INCrement by Two */
2193 /* (*S) +=2 */
2194 wadd(addr, 2);
2195 CYCLES(10, 3);
2196 break;
2197 case 8: /* DEC */
2198 /* DEC --- DECrement */
2199 /* (*S)-- */
2200 wsub(addr, 1);
2201 CYCLES(10, 3);
2202 break;
2203 case 9: /* DECT */
2204 /* DECT -- DECrement by Two */
2205 /* (*S) -= 2 */
2206 wsub(addr, 2);
2207 CYCLES(10, 3);
2208 break;
2209 case 10: /* BL */
2210 /* BL ---- Branch and Link */
2211 /* IP=S, R11=old IP */
2212 WRITEREG(R11, I.PC);
2213 I.PC = addr;
2214 CYCLES(12, 5);
2215 break;
2216 case 11: /* SWPB */
2217 /* SWPB -- SWaP Bytes */
2218 /* *S = swab(*S) */
2219 value = readword(addr);
2220 value = logical_right_shift(value, 8) | (value << 8);
2221 writeword(addr, value);
2222 CYCLES(10, 13);
2223 break;
2224 case 12: /* SETO */
2225 /* SETO -- SET Ones */
2226 /* *S = #$FFFF */
2227 writeword(addr, 0xFFFF);
2228 CYCLES(10, 3);
2229 break;
2230 case 13: /* ABS */
2231 /* ABS --- ABSolute value */
2232 /* *S = |*S| */
2233 /* clearing ST_C seems to be necessary, although ABS will never set it. */
2234 #if (TMS99XX_MODEL <= TMS9985_ID)
2235 /* tms9900/tms9980 only write the result if it has changed */
2236 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
2237 #if (TMS99XX_MODEL == TMS9940_ID)
2238 /* I guess ST_DC is cleared here, too*/
2239 I.STATUS &= ~ ST_DC;
2240 #endif
2241 value = readword(addr);
2242
2243 CYCLES(12, Mooof!);
2244
2245 if (((INT16) value) > 0)
2246 I.STATUS |= ST_LGT | ST_AGT;
2247 else if (((INT16) value) < 0)
2248 {
2249 I.STATUS |= ST_LGT;
2250 if (value == 0x8000)
2251 I.STATUS |= ST_OV;
2252 #if (TMS99XX_MODEL == TMS9940_ID)
2253 if (! (value & 0x0FFF))
2254 I.STATUS |= ST_DC;
2255 #endif
2256 writeword(addr, - ((INT16) value));
2257 CYCLES(2, Mooof!);
2258 }
2259 else
2260 I.STATUS |= ST_EQ;
2261
2262 #else
2263 /* tms9995 always write the result */
2264 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
2265 value = readword(addr);
2266
2267 CYCLES(12 /*Don't know for tms9989*/, 3);
2268 if (((INT16) value) > 0)
2269 I.STATUS |= ST_LGT | ST_AGT;
2270 else if (((INT16) value) < 0)
2271 {
2272 I.STATUS |= ST_LGT;
2273 if (value == 0x8000)
2274 I.STATUS |= ST_OV;
2275 value = - ((INT16) value);
2276 }
2277 else
2278 I.STATUS |= ST_EQ;
2279
2280 writeword(addr, value);
2281 #endif
2282
2283 break;
2284 #if (TMS99XX_MODEL >= TMS99105A_ID)
2285 /* "These opcode are designed to support the 99610 memory mapper, to allow easy access to
2286 another page without the need of switching a page someplace." */
2287 case 14: /* LDS */
2288 /* LDS --- Long Distance Source */
2289 /* ... */
2290 break;
2291 case 15: /* LDD */
2292 /* LDD --- Long Distance Destination */
2293 /* ... */
2294 break;
2295 #else
2296 default:
2297 /* illegal instructions */
2298 HANDLE_ILLEGAL;
2299 break;
2300 #endif
2301 }
2302 }
2303
2304
2305 /*==========================================================================
2306 Shift instructions, >0800->0BFF
2307 --------------------------------------------------------------------------
2308
2309 0 1 2 3-4 5 6 7+8 9 A B-C D E F
2310 ---------------------------------
2311 | o p c o d e | C | W |
2312 ---------------------------------
2313
2314 SRA, SRL, SLA, SRC
2315 ============================================================================*/
h0800(UINT16 opcode)2316 static void h0800(UINT16 opcode)
2317 {
2318 register UINT16 addr;
2319 register UINT16 cnt = (opcode & 0xF0) >> 4;
2320 register UINT16 value;
2321
2322 addr = (opcode & 0xF);
2323 addr = ((addr+addr) + I.WP) & ~1;
2324
2325 CYCLES(12, 5);
2326
2327 if (cnt == 0)
2328 {
2329 CYCLES(8, 2);
2330
2331 cnt = READREG(0) & 0xF;
2332
2333 if (cnt == 0)
2334 cnt = 16;
2335 }
2336
2337 CYCLES(cnt+cnt, cnt);
2338
2339 switch ((opcode & 0x300) >> 8)
2340 {
2341 case 0: /* SRA */
2342 /* SRA --- Shift Right Arithmetic */
2343 /* *W >>= C (*W is filled on the left with a copy of the sign bit) */
2344 value = setst_sra_laec(readword(addr), cnt);
2345 writeword(addr, value);
2346 break;
2347 case 1: /* SRL */
2348 /* SRL --- Shift Right Logical */
2349 /* *W >>= C (*W is filled on the left with 0) */
2350 value = setst_srl_laec(readword(addr), cnt);
2351 writeword(addr, value);
2352 break;
2353 case 2: /* SLA */
2354 /* SLA --- Shift Left Arithmetic */
2355 /* *W <<= C */
2356 value = setst_sla_laeco(readword(addr), cnt);
2357 writeword(addr, value);
2358 break;
2359 case 3: /* SRC */
2360 /* SRC --- Shift Right Circular */
2361 /* *W = rightcircularshift(*W, C) */
2362 value = setst_src_laec(readword(addr), cnt);
2363 writeword(addr, value);
2364 break;
2365 }
2366 }
2367
2368
2369 #if (TMS99XX_MODEL >= TMS99105A_ID)
2370 /*==========================================================================
2371 Additionnal instructions, >0C00->0C0F
2372 Additionnal single-register instructions, >0C10->0C3F
2373 ---------------------------------------------------------------------------
2374
2375 0 1 2 3-4 5 6 7+8 9 A B-C D E F
2376 ---------------------------------
2377 | o p c o d e |
2378 | o p c o d e | reg # |
2379 ---------------------------------
2380
2381 tms99xxx : TMB, TCMB, TSMB
2382 tms99110a : CRI, NEGR, CRE, CER
2383 ============================================================================*/
h0c00(UINT16 opcode)2384 static void h0c00(UINT16 opcode)
2385 {
2386 if (opcode & 0x30)
2387 {
2388 #if 0
2389 switch ((opcode & 0x30) >> 4)
2390 {
2391 case 1:
2392 /* INSF -- INSert Field */
2393 case 2:
2394 /* XV ---- eXtract Value */
2395 case 3:
2396 /* XF ---- eXtract Field */
2397
2398 break;
2399 }
2400 #else
2401 HANDLE_ILLEGAL;
2402 #endif
2403 }
2404 else
2405 {
2406 switch (opcode & 0x0F)
2407 {
2408 #if (TMS99XX_MODEL == TMS99110A_ID)
2409 /* floating point instructions */
2410 case 0:
2411 /* CRI --- Convert Real to Integer */
2412
2413 break;
2414 case 2:
2415 /* NEGR -- NEGate Real */
2416
2417 break;
2418 case 4:
2419 /* CRE --- Convert Real to Extended integer */
2420
2421 break;
2422 case 6:
2423 /* CER --- Convert Extended integer to Real */
2424
2425 break;
2426 #endif
2427
2428 /* The next three instructions allow to handle multiprocessor systems */
2429 case 9:
2430 /* TMB --- Test Memory Bit */
2431
2432 break;
2433 case 10:
2434 /* TCMB -- Test and Clear Memory Bit */
2435
2436 break;
2437 case 11:
2438 /* TSMB -- Test and Set Memory Bit */
2439
2440 break;
2441
2442 #if 0
2443 /* the four next instructions support BCD */
2444 case 1:
2445 /* CDI --- Convert Decimal to Integer */
2446 case 3:
2447 /* NEGD -- NEGate Decimal */
2448 case 5:
2449 /* CDE --- Convert Decimal to Extended integer */
2450 case 7:
2451 /* CED --- Convert Extended integer to Decimal */
2452
2453 case 8:
2454 /* NRM --- NoRMalize */
2455
2456 case 12:
2457 /* SRJ --- Subtract from Register and Jump */
2458 case 13:
2459 /* ARJ --- Add to Register and Jump */
2460
2461 case 14:
2462 case 15:
2463 /* XIT --- eXIT from floating point interpreter (???) */
2464 /* Completely alien to me. Must have existed on weird TI990 variants. */
2465
2466 break;
2467 #endif
2468 default:
2469 HANDLE_ILLEGAL;
2470 break;
2471 }
2472 }
2473 }
2474
2475
2476 /*==========================================================================
2477 Additionnal single-operand instructions, >0C40->0FFF
2478 ---------------------------------------------------------------------------
2479
2480 0 1 2 3-4 5 6 7+8 9 A B-C D E F
2481 ---------------------------------
2482 | o p c o d e |TS | S |
2483 ---------------------------------
2484
2485 tms99110a : AR, CIR, SR, MR, DR, LR, STR
2486 ============================================================================*/
h0c40(UINT16 opcode)2487 static void h0c40(UINT16 opcode)
2488 {
2489 register UINT16 src;
2490
2491 src = decipheraddr(opcode) & ~1;
2492
2493 switch ((opcode & 0x03C0) >> 6)
2494 {
2495 #if (TMS99XX_MODEL == TMS99110A_ID)
2496 case 1:
2497 /* AR ---- Add Real */
2498 case 2:
2499 /* CIR --- Convert Integer to Real */
2500 case 3:
2501 /* SR ---- Subtract Real */
2502 case 4:
2503 /* MR ---- Multiply Real */
2504 case 5:
2505 /* DR ---- Divide Real */
2506 case 6:
2507 /* LR ---- Load Real */
2508 case 7:
2509 /* STR --- STore Real */
2510 #endif
2511 #if 0
2512 case 9:
2513 /* AD ---- Add Decimal */
2514 case 10:
2515 /* CID --- Convert Integer to Decimal */
2516 case 11:
2517 /* SD ---- Subtract Decimal */
2518 case 12:
2519 /* MD ---- Multiply Decimal */
2520 case 13:
2521 /* DD ---- Divide Decimal */
2522 case 14:
2523 /* LD ---- Load Decimal */
2524 case 15:
2525 /* SD ---- Store Decimal */
2526 #endif
2527 default:
2528 HANDLE_ILLEGAL;
2529 break;
2530 }
2531 }
2532 #endif
2533
2534
2535 /*==========================================================================
2536 Jump, CRU bit instructions, >1000->1FFF
2537 ---------------------------------------------------------------------------
2538
2539 0 1 2 3-4 5 6 7+8 9 A B-C D E F
2540 ---------------------------------
2541 | o p c o d e | signed offset |
2542 ---------------------------------
2543
2544 JMP, JLT, JLE, JEQ, JHE, JGT, JNE, JNC, JOC, JNO, JL, JH, JOP
2545 SBO, SBZ, TB
2546 ============================================================================*/
h1000(UINT16 opcode)2547 static void h1000(UINT16 opcode)
2548 {
2549 /* we convert 8 bit signed word offset to a 16 bit effective word offset. */
2550 register INT16 offset = ((INT8) opcode);
2551
2552
2553 switch ((opcode & 0xF00) >> 8)
2554 {
2555 case 0: /* JMP */
2556 /* JMP --- unconditional JuMP */
2557 /* PC += offset */
2558 I.PC += (offset + offset);
2559 CYCLES(10, 3);
2560 break;
2561 case 1: /* JLT */
2562 /* JLT --- Jump if Less Than (arithmetic) */
2563 /* if (A==0 && EQ==0), PC += offset */
2564 if (! (I.STATUS & (ST_AGT | ST_EQ)))
2565 {
2566 I.PC += (offset + offset);
2567 CYCLES(10, 3);
2568 }
2569 else
2570 CYCLES(8, 3);
2571 break;
2572 case 2: /* JLE */
2573 /* JLE --- Jump if Lower or Equal (logical) */
2574 /* if (L==0 || EQ==1), PC += offset */
2575 if ((! (I.STATUS & ST_LGT)) || (I.STATUS & ST_EQ))
2576 {
2577 I.PC += (offset + offset);
2578 CYCLES(10, 3);
2579 }
2580 else
2581 CYCLES(8, 3);
2582 break;
2583 case 3: /* JEQ */
2584 /* JEQ --- Jump if EQual */
2585 /* if (EQ==1), PC += offset */
2586 if (I.STATUS & ST_EQ)
2587 {
2588 I.PC += (offset + offset);
2589 CYCLES(10, 3);
2590 }
2591 else
2592 CYCLES(8, 3);
2593 break;
2594 case 4: /* JHE */
2595 /* JHE --- Jump if Higher or Equal (logical) */
2596 /* if (L==1 || EQ==1), PC += offset */
2597 if (I.STATUS & (ST_LGT | ST_EQ))
2598 {
2599 I.PC += (offset + offset);
2600 CYCLES(10, 3);
2601 }
2602 else
2603 CYCLES(8, 3);
2604 break;
2605 case 5: /* JGT */
2606 /* JGT --- Jump if Greater Than (arithmetic) */
2607 /* if (A==1), PC += offset */
2608 if (I.STATUS & ST_AGT)
2609 {
2610 I.PC += (offset + offset);
2611 CYCLES(10, 3);
2612 }
2613 else
2614 CYCLES(8, 3);
2615 break;
2616 case 6: /* JNE */
2617 /* JNE --- Jump if Not Equal */
2618 /* if (EQ==0), PC += offset */
2619 if (! (I.STATUS & ST_EQ))
2620 {
2621 I.PC += (offset + offset);
2622 CYCLES(10, 3);
2623 }
2624 else
2625 CYCLES(8, 3);
2626 break;
2627 case 7: /* JNC */
2628 /* JNC --- Jump if No Carry */
2629 /* if (C==0), PC += offset */
2630 if (! (I.STATUS & ST_C))
2631 {
2632 I.PC += (offset + offset);
2633 CYCLES(10, 3);
2634 }
2635 else
2636 CYCLES(8, 3);
2637 break;
2638 case 8: /* JOC */
2639 /* JOC --- Jump On Carry */
2640 /* if (C==1), PC += offset */
2641 if (I.STATUS & ST_C)
2642 {
2643 I.PC += (offset + offset);
2644 CYCLES(10, 3);
2645 }
2646 else
2647 CYCLES(8, 3);
2648 break;
2649 case 9: /* JNO */
2650 /* JNO --- Jump if No Overflow */
2651 /* if (OV==0), PC += offset */
2652 if (! (I.STATUS & ST_OV))
2653 {
2654 I.PC += (offset + offset);
2655 CYCLES(10, 3);
2656 }
2657 else
2658 CYCLES(8, 3);
2659 break;
2660 case 10: /* JL */
2661 /* JL ---- Jump if Lower (logical) */
2662 /* if (L==0 && EQ==0), PC += offset */
2663 if (! (I.STATUS & (ST_LGT | ST_EQ)))
2664 {
2665 I.PC += (offset + offset);
2666 CYCLES(10, 3);
2667 }
2668 else
2669 CYCLES(8, 3);
2670 break;
2671 case 11: /* JH */
2672 /* JH ---- Jump if Higher (logical) */
2673 /* if (L==1 && EQ==0), PC += offset */
2674 if ((I.STATUS & ST_LGT) && ! (I.STATUS & ST_EQ))
2675 {
2676 I.PC += (offset + offset);
2677 CYCLES(10, 3);
2678 }
2679 else
2680 CYCLES(8, 3);
2681 break;
2682 case 12: /* JOP */
2683 /* JOP --- Jump On (odd) Parity */
2684 /* if (P==1), PC += offset */
2685 {
2686 /* Let's set ST_OP. */
2687 int i;
2688 UINT8 a;
2689 a = lastparity;
2690 i = 0;
2691
2692 while (a != 0)
2693 {
2694 if (a & 1) /* If current bit is set, */
2695 i++; /* increment bit count. */
2696 a >>= 1U; /* Next bit. */
2697 }
2698
2699 /* Set ST_OP bit. */
2700 /*if (i & 1)
2701 I.STATUS |= ST_OP;
2702 else
2703 I.STATUS &= ~ ST_OP;*/
2704
2705 /* Jump accordingly. */
2706 if (i & 1) /*(I.STATUS & ST_OP)*/
2707 {
2708 I.PC += (offset + offset);
2709 CYCLES(10, 3);
2710 }
2711 else
2712 CYCLES(8, 3);
2713 }
2714
2715 break;
2716 case 13: /* SBO */
2717 /* SBO --- Set Bit to One */
2718 /* CRU Bit = 1 */
2719 writeCRU((READREG(R12) >> 1) + offset, 1, 1);
2720 CYCLES(12, 8);
2721 break;
2722 case 14: /* SBZ */
2723 /* SBZ --- Set Bit to Zero */
2724 /* CRU Bit = 0 */
2725 writeCRU((READREG(R12) >> 1) + offset, 1, 0);
2726 CYCLES(12, 8);
2727 break;
2728 case 15: /* TB */
2729 /* TB ---- Test Bit */
2730 /* EQ = (CRU Bit == 1) */
2731 setst_e(readCRU((READREG(R12)>> 1) + offset, 1) & 1, 1);
2732 CYCLES(12, 8);
2733 break;
2734 }
2735 }
2736
2737
2738 /*==========================================================================
2739 General and One-Register instructions >2000->3FFF
2740 ---------------------------------------------------------------------------
2741
2742 0 1 2 3-4 5 6 7+8 9 A B-C D E F
2743 ---------------------------------
2744 | opcode | D |TS | S |
2745 ---------------------------------
2746
2747 COC, CZC, XOR, LDCR, STCR, XOP, MPY, DIV
2748 tms9940 : DCA, DCS, LIIM
2749 ==========================================================================*/
2750
2751 /* xop, ldcr and stcr are handled elsewhere */
h2000(UINT16 opcode)2752 static void h2000(UINT16 opcode)
2753 {
2754 register UINT16 dest = (opcode & 0x3C0) >> 6;
2755 register UINT16 src;
2756 register UINT16 value;
2757
2758 src = decipheraddr(opcode);
2759
2760 switch ((opcode & 0x1C00) >> 10)
2761 {
2762 case 0: /* COC */
2763 /* COC --- Compare Ones Corresponding */
2764 /* status E bit = (S&D == S) */
2765 dest = ((dest+dest) + I.WP) & ~1;
2766 src &= ~1;
2767 value = readword(src);
2768 setst_e(value & readword(dest), value);
2769 CYCLES(14, 4);
2770 break;
2771 case 1: /* CZC */
2772 /* CZC --- Compare Zeroes Corresponding */
2773 /* status E bit = (S&~D == S) */
2774 dest = ((dest+dest) + I.WP) & ~1;
2775 src &= ~1;
2776 value = readword(src);
2777 setst_e(value & (~ readword(dest)), value);
2778 CYCLES(14, 4);
2779 break;
2780 case 2: /* XOR */
2781 /* XOR --- eXclusive OR */
2782 /* D ^= S */
2783 dest = ((dest+dest) + I.WP) & ~1;
2784 src &= ~1;
2785 value = readword(dest) ^ readword(src);
2786 setst_lae(value);
2787 writeword(dest,value);
2788 CYCLES(14, 4);
2789 break;
2790 /*case 3:*/ /* XOP is implemented elsewhere */
2791 /*case 4:*/ /* LDCR is implemented elsewhere */
2792 /*case 5:*/ /* STCR is implemented elsewhere */
2793 case 6: /* MPY */
2794 /* MPY --- MultiPlY (unsigned) */
2795 /* Results: D:D+1 = D*S */
2796 /* Note that early TMS9995 reportedly perform an extra dummy read in PC space */
2797 dest = ((dest+dest) + I.WP) & ~1;
2798 src &= ~1;
2799 {
2800 unsigned long prod = ((unsigned long) readword(dest)) * ((unsigned long) readword(src));
2801 writeword(dest, prod >> 16);
2802 writeword(dest+2, prod);
2803 }
2804 CYCLES(52, 23);
2805 break;
2806 case 7: /* DIV */
2807 /* DIV --- DIVide (unsigned) */
2808 /* D = D/S D+1 = D%S */
2809 dest = ((dest+dest) + I.WP) & ~1;
2810 src &= ~1;
2811 {
2812 UINT16 d = readword(src);
2813 UINT16 hi = readword(dest);
2814 unsigned long divq = (((unsigned long) hi) << 16) | readword(dest+2);
2815
2816 if (d <= hi)
2817 {
2818 I.STATUS |= ST_OV;
2819 CYCLES(16, 6);
2820 }
2821 else
2822 {
2823 I.STATUS &= ~ST_OV;
2824 writeword(dest, divq/d);
2825 writeword(dest+2, divq%d);
2826 /* tms9900 : from 92 to 124, possibly 92 + 2*(number of bits to 1 (or 0?) in quotient) */
2827 /* tms9995 : 28 is the worst case */
2828 CYCLES(92, 28);
2829 }
2830 }
2831 break;
2832 }
2833 }
2834
xop(UINT16 opcode)2835 static void xop(UINT16 opcode)
2836 { /* XOP */
2837 /* XOP --- eXtended OPeration */
2838 /* WP = *(40h+D), PC = *(42h+D) */
2839 /* New R13=old WP, New R14=Old IP, New R15=Old ST */
2840 /* New R11=S */
2841 /* Xop bit set */
2842
2843 register UINT16 immediate = (opcode & 0x3C0) >> 6;
2844 register UINT16 operand;
2845
2846 #if (TMS99XX_MODEL == TMS9940_ID)
2847 switch (immediate)
2848 {
2849 case 0: /* DCA */
2850 /* DCA --- Decimal Correct Addition */
2851 operand = decipheraddrbyte(opcode);
2852 {
2853 int value = readbyte(operand);
2854 int X = (value >> 4) & 0xf;
2855 int Y = value & 0xf;
2856
2857 if (Y >= 10)
2858 {
2859 Y -= 10;
2860 I.STATUS |= ST_DC;
2861 X++;
2862 }
2863 else if (I.STATUS & ST_DC)
2864 {
2865 Y += 6;
2866 }
2867
2868 if (X >= 10)
2869 {
2870 X -= 10;
2871 I.STATUS |= ST_C;
2872 }
2873 else if (I.STATUS & ST_C)
2874 {
2875 X += 6;
2876 }
2877
2878 writebyte(operand, (X << 4) | Y);
2879 }
2880 break;
2881 case 1: /* DCS */
2882 /* DCS --- Decimal Correct Substraction */
2883 operand = decipheraddrbyte(opcode);
2884 {
2885 int value = readbyte(operand);
2886
2887 if (! (I.STATUS & ST_DC))
2888 {
2889 value += 10;
2890 }
2891
2892 if (! (I.STATUS & ST_C))
2893 {
2894 value += 10 << 4;
2895 }
2896
2897 I.STATUS ^= ST_DC;
2898
2899 writebyte(operand, value);
2900 }
2901 break;
2902 case 2: /* LIIM */
2903 case 3: /* LIIM */
2904 /* LIIM - Load Immediate Interrupt Mask */
2905 /* Does the same job as LIMI, with a different opcode format. */
2906 /* Note that, unlike TMS9900, the interrupt mask is only 2-bit long. */
2907 operand = decipheraddr(opcode); /* dummy decode (personnal guess) */
2908
2909 I.STATUS = (I.STATUS & 0xFFFC) | (opcode & 0x0003);
2910 break;
2911 default: /* normal XOP */
2912 #endif
2913
2914 operand = decipheraddr(opcode);
2915
2916 #if (TMS99XX_MODEL <= TMS9989_ID)
2917 (void)readword(operand & ~1); /*dummy read (personnal guess)*/
2918 #endif
2919
2920 contextswitch(0x40 + (immediate << 2));
2921 #if (TMS99XX_MODEL != TMS9940_ID)
2922 /* The bit is not set on tms9940 */
2923 I.STATUS |= ST_X;
2924 #endif
2925 WRITEREG(R11, operand);
2926 CYCLES(36, 15);
2927 disable_interrupt_recognition = 1;
2928
2929 #if (TMS99XX_MODEL == TMS9940_ID)
2930 break;
2931 }
2932 #endif
2933 }
2934
2935 /* LDCR and STCR */
ldcr_stcr(UINT16 opcode)2936 static void ldcr_stcr(UINT16 opcode)
2937 {
2938 register UINT16 cnt = (opcode & 0x3C0) >> 6;
2939 register UINT16 addr;
2940 register UINT16 value;
2941
2942 if (cnt == 0)
2943 cnt = 16;
2944
2945 if (cnt <= 8)
2946 addr = decipheraddrbyte(opcode);
2947 else
2948 addr = decipheraddr(opcode) & ~1;
2949
2950 if (opcode < 0x3400)
2951 { /* LDCR */
2952 /* LDCR -- LoaD into CRu */
2953 /* CRU R12--CRU R12+D-1 set to S */
2954 if (cnt <= 8)
2955 {
2956 #if (TMS99XX_MODEL != TMS9995_ID)
2957 value = readbyte(addr);
2958 #else
2959 /* just for once, tms9995 behaves like earlier 8-bit tms99xx chips */
2960 /* this must be because instruction decoding is too complex */
2961 value = readword(addr);
2962 if (addr & 1)
2963 value &= 0xFF;
2964 else
2965 value = (value >> 8) & 0xFF;
2966 #endif
2967 (void)READREG(cnt+cnt); /*dummy read (reasonnable guess, cf TMS9995)*/
2968 setst_byte_laep(value);
2969 writeCRU((READREG(R12) >> 1), cnt, value);
2970 }
2971 else
2972 {
2973 value = readword(addr);
2974 (void)READREG(cnt+cnt); /*dummy read (reasonnable guess, cf TMS9995)*/
2975 setst_lae(value);
2976 writeCRU((READREG(R12) >> 1), cnt, value);
2977 }
2978 CYCLES(20 + cnt+cnt, 9 + cnt+cnt);
2979 }
2980 else
2981 { /* STCR */
2982 /* STCR -- STore from CRu */
2983 /* S = CRU R12--CRU R12+D-1 */
2984 if (cnt <= 8)
2985 {
2986 #if (TMS99XX_MODEL != TMS9995_ID)
2987 (void)readbyte(addr); /*dummy read*/
2988 (void)READREG(cnt+cnt); /*dummy read (reasonnable guess, cf TMS9995)*/
2989 value = readCRU((READREG(R12) >> 1), cnt);
2990 setst_byte_laep(value);
2991 writebyte(addr, value);
2992 CYCLES((cnt != 8) ? 42 : 44, 19 + cnt);
2993 #else
2994 /* just for once, tms9995 behaves like earlier 8-bit tms99xx chips */
2995 /* this must be because instruction decoding is too complex */
2996 int value2 = readword(addr);
2997
2998 READREG(cnt+cnt); /*dummy read (guessed from timing table)*/
2999 value = readCRU((READREG(R12) >> 1), cnt);
3000 setst_byte_laep(value);
3001
3002 if (addr & 1)
3003 writeword(addr, (value & 0x00FF) | (value2 & 0xFF00));
3004 else
3005 writeword(addr, (value2 & 0x00FF) | ((value << 8) & 0xFF00));
3006
3007 CYCLES(Mooof!, 19 + cnt);
3008 #endif
3009 }
3010 else
3011 {
3012 (void)readword(addr); /*dummy read*/
3013 (void)READREG(cnt+cnt); /*dummy read (reasonnable guess, cf TMS9995)*/
3014 value = readCRU((READREG(R12) >> 1), cnt);
3015 setst_lae(value);
3016 writeword(addr, value);
3017 CYCLES((cnt != 16) ? 58 : 60, 27 + cnt);
3018 }
3019 }
3020 }
3021
3022
3023 /*==========================================================================
3024 Two-Operand instructions >4000->FFFF
3025 ---------------------------------------------------------------------------
3026
3027 0 1 2 3-4 5 6 7+8 9 A B-C D E F
3028 ----------------------------------
3029 |opcode|B|TD | D |TS | S |
3030 ----------------------------------
3031
3032 SZC, SZCB, S, SB, C, CB, A, AB, MOV, MOVB, SOC, SOCB
3033 ============================================================================*/
3034
3035 /* word instructions */
h4000w(UINT16 opcode)3036 static void h4000w(UINT16 opcode)
3037 {
3038 register UINT16 src;
3039 register UINT16 dest;
3040 register UINT16 value;
3041
3042 src = decipheraddr(opcode) & ~1;
3043 dest = decipheraddr(opcode >> 6) & ~1;
3044
3045 switch ((opcode >> 13) & 0x0007) /* ((opcode & 0xE000) >> 13) */
3046 {
3047 case 2: /* SZC */
3048 /* SZC --- Set Zeros Corresponding */
3049 /* D &= ~S */
3050 value = readword(dest) & (~ readword(src));
3051 setst_lae(value);
3052 writeword(dest, value);
3053 CYCLES(14, 4);
3054 break;
3055 case 3: /* S */
3056 /* S ----- Subtract */
3057 /* D -= S */
3058 value = setst_sub_laeco(readword(dest), readword(src));
3059 writeword(dest, value);
3060 CYCLES(14, 4);
3061 break;
3062 case 4: /* C */
3063 /* C ----- Compare */
3064 /* ST = (D - S) */
3065 setst_c_lae(readword(dest), readword(src));
3066 CYCLES(14, 4);
3067 break;
3068 case 5: /* A */
3069 /* A ----- Add */
3070 /* D += S */
3071 value = setst_add_laeco(readword(dest), readword(src));
3072 writeword(dest, value);
3073 CYCLES(14, 4);
3074 break;
3075 case 6: /* MOV */
3076 /* MOV --- MOVe */
3077 /* D = S */
3078 value = readword(src);
3079 setst_lae(value);
3080 #if (TMS99XX_MODEL <= TMS9989_ID)
3081 /* MOV performs a dummy read... */
3082 (void)readword(dest);
3083 #endif
3084 writeword(dest, value);
3085 CYCLES(14, 3);
3086 break;
3087 case 7: /* SOC */
3088 /* SOC --- Set Ones Corresponding */
3089 /* D |= S */
3090 value = readword(dest) | readword(src);
3091 setst_lae(value);
3092 writeword(dest, value);
3093 CYCLES(14, 4);
3094 break;
3095 }
3096 }
3097
3098 /* byte instruction */
h4000b(UINT16 opcode)3099 static void h4000b(UINT16 opcode)
3100 {
3101 register UINT16 src;
3102 register UINT16 dest;
3103 register UINT16 value;
3104
3105 src = decipheraddrbyte(opcode);
3106 dest = decipheraddrbyte(opcode >> 6);
3107
3108 switch ((opcode >> 13) & 0x0007) /* ((opcode & 0xE000) >> 13) */
3109 {
3110 case 2: /* SZCB */
3111 /* SZCB -- Set Zeros Corresponding, Byte */
3112 /* D &= ~S */
3113 value = readbyte(dest) & (~ readbyte(src));
3114 setst_byte_laep(value);
3115 writebyte(dest, value);
3116 CYCLES(14, 4);
3117 break;
3118 case 3: /* SB */
3119 /* SB ---- Subtract, Byte */
3120 /* D -= S */
3121 value = setst_subbyte_laecop(readbyte(dest), readbyte(src));
3122 writebyte(dest, value);
3123 CYCLES(14, 4);
3124 break;
3125 case 4: /* CB */
3126 /* CB ---- Compare Bytes */
3127 /* ST = (D - S) */
3128 value = readbyte(src);
3129 setst_c_lae(readbyte(dest)<<8, value<<8);
3130 lastparity = value;
3131 CYCLES(14, 4);
3132 break;
3133 case 5: /* AB */
3134 /* AB ---- Add, Byte */
3135 /* D += S */
3136 value = setst_addbyte_laecop(readbyte(dest), readbyte(src));
3137 writebyte(dest, value);
3138 break;
3139 case 6: /* MOVB */
3140 /* MOVB -- MOVe Bytes */
3141 /* D = S */
3142 value = readbyte(src);
3143 setst_byte_laep(value);
3144 #if (TMS99XX_MODEL <= TMS9989_ID)
3145 /* on tms9900, MOVB needs to read destination, because it cannot actually read one single byte.
3146 It reads a word, replaces the revelant byte, then write the result */
3147 /* A tms9980 theorically does not need to do so, but still does... */
3148 readbyte(dest);
3149 #endif
3150 writebyte(dest, value);
3151 CYCLES(14, 3);
3152 break;
3153 case 7: /* SOCB */
3154 /* SOCB -- Set Ones Corresponding, Byte */
3155 /* D |= S */
3156 value = readbyte(dest) | readbyte(src);
3157 setst_byte_laep(value);
3158 writebyte(dest, value);
3159 CYCLES(14, 4);
3160 break;
3161 }
3162 }
3163
3164
execute(UINT16 opcode)3165 static INLINE void execute(UINT16 opcode)
3166 {
3167 #if (TMS99XX_MODEL <= TMS9985_ID)
3168
3169 /* tms9900-like instruction set*/
3170
3171 static void (* jumptable[128])(UINT16) =
3172 {
3173 &illegal,&h0200,&h0400,&h0400,&h0800,&h0800,&illegal,&illegal,
3174 &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
3175 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&xop,&xop,
3176 &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&h2000,&h2000,&h2000,&h2000,
3177 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3178 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3179 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3180 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3181 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3182 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3183 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3184 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3185 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3186 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3187 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3188 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b
3189 };
3190
3191 (* jumptable[opcode >> 9])(opcode);
3192
3193 #elif (TMS99XX_MODEL <= TMS9995_ID)
3194
3195 /* tms9989 and tms9995 include 4 extra instructions, and one additionnal instruction type */
3196
3197 static void (* jumptable[256])(UINT16) =
3198 {
3199 &h0040,&h0100,&h0200,&h0200,&h0400,&h0400,&h0400,&h0400,
3200 &h0800,&h0800,&h0800,&h0800,&illegal,&illegal,&illegal,&illegal,
3201 &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
3202 &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
3203 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3204 &h2000,&h2000,&h2000,&h2000,&xop,&xop,&xop,&xop,
3205 &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,
3206 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3207 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3208 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3209 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3210 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3211 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3212 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3213 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3214 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3215 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3216 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3217 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3218 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3219 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3220 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3221 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3222 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3223 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3224 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3225 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3226 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3227 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3228 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3229 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3230 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b
3231 };
3232
3233 (* jumptable[opcode >> 8])(opcode);
3234
3235 #elif (TMS99XX_MODEL >= TMS99105A_ID)
3236
3237 /* tms99xxx include even more instruction types */
3238
3239 static void (* jumptable[1024])(UINT16) =
3240 {
3241 &h0000,&h0040,&h0040,&illegal,&h0100,&h0100,&h0100,&h0100,
3242 &h0200,&h0200,&h0200,&h0200,&h0200,&h0200,&h0200,&h0200,
3243 &h0400,&h0400,&h0400,&h0400,&h0400,&h0400,&h0400,&h0400,
3244 &h0400,&h0400,&h0400,&h0400,&h0400,&h0400,&h0400,&h0400,
3245 &h0800,&h0800,&h0800,&h0800,&h0800,&h0800,&h0800,&h0800,
3246 &h0800,&h0800,&h0800,&h0800,&h0800,&h0800,&h0800,&h0800,
3247 #if (TMS99XX_MODEL == TMS99110A_ID)
3248 &h0c00,&h0c40,&h0c40,&h0c40,&h0c40,&h0c40,&h0c40,&h0c40,
3249 #else
3250 &h0c00,&illegal,&illegal,&illegal,&illegal,&illegal,&illegal,&illegal,
3251 #endif
3252 &illegal,&illegal,&illegal,&illegal,&illegal,&illegal,&illegal,&illegal,
3253 &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
3254 &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
3255 &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
3256 &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
3257 &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
3258 &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
3259 &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
3260 &h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,&h1000,
3261 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3262 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3263 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3264 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3265 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3266 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3267 &xop,&xop,&xop,&xop,&xop,&xop,&xop,&xop,
3268 &xop,&xop,&xop,&xop,&xop,&xop,&xop,&xop,
3269 &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,
3270 &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,
3271 &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,
3272 &ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,&ldcr_stcr,
3273 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3274 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3275 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3276 &h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,&h2000,
3277 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3278 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3279 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3280 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3281 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3282 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3283 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3284 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3285 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3286 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3287 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3288 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3289 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3290 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3291 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3292 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3293 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3294 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3295 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3296 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3297 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3298 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3299 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3300 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3301 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3302 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3303 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3304 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3305 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3306 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3307 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3308 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3309 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3310 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3311 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3312 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3313 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3314 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3315 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3316 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3317 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3318 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3319 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3320 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3321 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3322 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3323 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3324 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3325 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3326 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3327 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3328 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3329 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3330 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3331 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3332 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3333 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3334 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3335 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3336 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3337 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3338 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3339 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3340 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3341 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3342 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3343 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3344 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3345 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3346 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3347 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3348 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3349 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3350 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3351 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3352 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3353 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3354 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3355 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3356 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3357 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3358 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3359 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3360 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3361 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3362 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3363 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3364 &h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,&h4000w,
3365 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3366 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3367 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3368 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3369 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3370 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3371 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,
3372 &h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b,&h4000b
3373 };
3374
3375 (* jumptable[opcode >> 6])(opcode);
3376
3377 #endif
3378 }
3379