1 /************************************************************************
2
3 ST register functions
4
5 ************************************************************************/
6
7 /*
8 remember that the OP ST bit is maintained in lastparity
9 */
10
11 /*
12 setstat sets the ST_OP bit according to lastparity
13
14 It must be called before reading the ST register.
15 */
16
setstat(void)17 static void setstat(void)
18 {
19 int i;
20 UINT8 a;
21
22 I.STATUS &= ~ ST_OP;
23
24 /* We set the parity bit. */
25 a = lastparity;
26
27 for (i=0; i<8; i++) /* 8 bits to test */
28 {
29 if (a & 1) /* If current bit is set */
30 I.STATUS ^= ST_OP; /* we toggle the ST_OP bit */
31
32 a >>= 1; /* Next bit. */
33 }
34 }
35
36 /*
37 getstat sets emulator's lastparity variable according to 9900's STATUS bits.
38 It must be called on interrupt return, or when, for some reason,
39 the emulated program sets the STATUS register directly.
40 */
getstat(void)41 static void getstat(void)
42 {
43 #if TMS99XX_MODEL <= TMS9985_ID
44 I.STATUS &= ST_MASK; /* unused bits are forced to 0 */
45 #endif
46
47 if (I.STATUS & ST_OP)
48 lastparity = 1;
49 else
50 lastparity = 0;
51 }
52
53 /*
54 A few words about the following functions.
55
56 A big portability issue is the behavior of the ">>" instruction with the sign bit, which has
57 not been normalised. Every compiler does whatever it thinks smartest.
58 My code assumed that when shifting right signed numbers, the operand is left-filled with a
59 copy of sign bit, and that when shifting unsigned variables, it is left-filled with 0s.
60 This is probably the most logical behaviour, and it is the behavior of CW PRO3 - most time
61 (the exception is that ">>=" instructions always copy the sign bit (!)). But some compilers
62 are bound to disagree.
63
64 So, I had to create special functions with predefined tables included, so that this code work
65 on every compiler. BUT this is a real slow-down.
66 So, you might have to include a few lines in assembly to make this work better.
67 Sorry about this, this problem is really unpleasant and absurd, but it is not my fault.
68 */
69
70
71 static const UINT16 right_shift_mask_table[17] =
72 {
73 0xFFFF,
74 0x7FFF,
75 0x3FFF,
76 0x1FFF,
77 0x0FFF,
78 0x07FF,
79 0x03FF,
80 0x01FF,
81 0x00FF,
82 0x007F,
83 0x003F,
84 0x001F,
85 0x000F,
86 0x0007,
87 0x0003,
88 0x0001,
89 0x0000
90 };
91
92 static const UINT16 inverted_right_shift_mask_table[17] =
93 {
94 0x0000,
95 0x8000,
96 0xC000,
97 0xE000,
98 0xF000,
99 0xF800,
100 0xFC00,
101 0xFE00,
102 0xFF00,
103 0xFF80,
104 0xFFC0,
105 0xFFE0,
106 0xFFF0,
107 0xFFF8,
108 0xFFFC,
109 0xFFFE,
110 0xFFFF
111 };
112
logical_right_shift(UINT16 val,int c)113 static INLINE UINT16 logical_right_shift(UINT16 val, int c)
114 {
115 return((val>>c) & right_shift_mask_table[c]);
116 }
117
arithmetic_right_shift(INT16 val,int c)118 static INLINE INT16 arithmetic_right_shift(INT16 val, int c)
119 {
120 if (val < 0)
121 return((val>>c) | inverted_right_shift_mask_table[c]);
122 else
123 return((val>>c) & right_shift_mask_table[c]);
124 }
125
126
127
128
129
130 /*
131 Set lae
132 */
setst_lae(INT16 val)133 static INLINE void setst_lae(INT16 val)
134 {
135 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
136
137 if (val > 0)
138 I.STATUS |= (ST_LGT | ST_AGT);
139 else if (val < 0)
140 I.STATUS |= ST_LGT;
141 else
142 I.STATUS |= ST_EQ;
143 }
144
145
146 /*
147 Set laep (BYTE)
148 */
setst_byte_laep(INT8 val)149 static INLINE void setst_byte_laep(INT8 val)
150 {
151 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
152
153 if (val > 0)
154 I.STATUS |= (ST_LGT | ST_AGT);
155 else if (val < 0)
156 I.STATUS |= ST_LGT;
157 else
158 I.STATUS |= ST_EQ;
159
160 lastparity = val;
161 }
162
163 /*
164 For COC, CZC, and TB
165 */
setst_e(UINT16 val,UINT16 to)166 static INLINE void setst_e(UINT16 val, UINT16 to)
167 {
168 if (val == to)
169 I.STATUS |= ST_EQ;
170 else
171 I.STATUS &= ~ ST_EQ;
172 }
173
174 /*
175 For CI, C, CB
176 */
setst_c_lae(UINT16 to,UINT16 val)177 static INLINE void setst_c_lae(UINT16 to, UINT16 val)
178 {
179 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ);
180
181 if (val == to)
182 I.STATUS |= ST_EQ;
183 else
184 {
185 if ( ((INT16) val) > ((INT16) to) )
186 I.STATUS |= ST_AGT;
187 if ( ((UINT16) val) > ((UINT16) to) )
188 I.STATUS |= ST_LGT;
189 }
190 }
191
192 #define wadd(addr,expr) { int lval = setst_add_laeco(readword(addr), (expr)); writeword((addr),lval); }
193 #define wsub(addr,expr) { int lval = setst_sub_laeco(readword(addr), (expr)); writeword((addr),lval); }
194
195 #if defined(__POWERPC__) && !defined(__GNUC__) && !defined(_XBOX)
196
197 // setst_add_32_laeco :
198 // - computes a+b
199 // - sets L, A, E, Carry and Overflow in st
200 //
201 // a -> r3, b -> r4, st -> r5
202 // preserve r6-r12
203
setst_add_32_laeco(register INT32 a,register INT32 b,register INT16 st)204 static INT32 asm setst_add_32_laeco(register INT32 a, register INT32 b, register INT16 st)
205 {
206 #if (TMS99XX_MODEL == TMS9940_ID)
207 mr r6,a // save operand
208 #endif
209 addco. r3, b, a // add, set CR0, and set CA and OV
210 clrlwi st, st, 21 // clear L, A, E, C, O flags (-> keep bits 21-31)
211 mcrxr cr1 // move XER (-> CA and CO bits) to CR1
212
213 beq- null_result // if EQ is set, jump to null_result. No jump is more likely than a jump.
214 bgt+ positive_result // if GT is set, jump to positive_result. A jump is more likely than no jump.
215 ori st, st, ST_LGT // if result < 0, set ST_LGT
216 b next // now set carry & overflow as needed
217
218 null_result:
219 ori st, st, ST_EQ // if result == 0, set ST_EQ
220 b next
221
222 positive_result:
223 ori st, st, ST_LGT | ST_AGT // if result > 0, set ST_LGT and ST_AGT
224
225 next:
226 #if (TMS99XX_MODEL == TMS9940_ID)
227 andi. st, st, (~ ST_DC) & 0xFFFF
228
229 or r7,r6,b
230 and r6,r6,b
231 andc r7,r7,r3
232 or r6,r7,r6
233 andis. r6,r6,0x0800
234 beq+ nodecimalcarry
235 ori st, st, ST_DC
236 nodecimalcarry:
237 #endif
238
239 bf+ cr1*4+2, nocarry // if CA is not set, jump to nocarry. A jump is more likely than no jump.
240 ori st, st, ST_C // else set ST_C
241 nocarry:
242 bflr+ cr1*4+1 // if OV is not set, return. A jump is more likely than no jump.
243 ori st, st, ST_OV // else set ST_OV
244 blr // return
245 }
246
247 // setst_sub_32_laeco :
248 // - computes a-b
249 // - sets L, A, E, Carry and Overflow in ST
250 //
251 // a -> r3, b -> r4, st -> r5
252 // preserve r6-r12
253
setst_sub_32_laeco(register INT32 a,register INT32 b,register INT16 st)254 static INT32 asm setst_sub_32_laeco(register INT32 a, register INT32 b, register INT16 st)
255 {
256 #if (TMS99XX_MODEL == TMS9940_ID)
257 mr r6,a // save operand
258 #endif
259 subco. r3, a, b // sub, set CR0, and set CA and OV
260 clrlwi st, st, 21 // clear L, A, E, C, O flags (-> keep bits 21-31)
261 mcrxr cr1 // move XER (-> CA and CO bits) to CR1
262
263 beq- null_result // if EQ is set, jump to null_result. No jump is more likely than a jump.
264 bgt+ positive_result // if GT is set, jump to positive_result. A jump is more likely than no jump.
265 ori st, st, ST_LGT // if result < 0, set ST_LGT
266 b next // now set carry & overflow as needed
267
268 null_result:
269 ori st, st, ST_EQ // if result == 0, set ST_EQ
270 b next
271
272 positive_result:
273 ori st, st, ST_LGT | ST_AGT // if result > 0, set ST_LGT and ST_AGT
274
275 next:
276 #if (TMS99XX_MODEL == TMS9940_ID)
277 andi. st, st, (~ ST_DC) & 0xFFFF
278
279 orc r7,r6,b
280 andc r6,r6,b
281 andc r7,r7,r3
282 or r6,r7,r6
283 andis. r6,r6,0x0800
284 beq- nodecimalcarry
285 ori st, st, ST_DC
286 nodecimalcarry:
287 #endif
288
289 bf- cr1*4+2, nocarry // if CA is not set, jump to nocarry. No jump is more likely than a jump.
290 ori st, st, ST_C // else set ST_C
291 nocarry:
292 bflr+ cr1*4+1 // if OV is not set, return. A jump is more likely than no jump.
293 ori st, st, ST_OV // else set ST_OV
294 blr // return
295 }
296
297 //
298 // Set laeco for add
299 //
setst_add_laeco(register INT16 a,register INT16 b)300 static INT16 asm setst_add_laeco(register INT16 a, register INT16 b)
301 { // a -> r3, b -> r4
302 // lwz r6, I(RTOC) // load pointer to I
303 _asm_get_global(r6,I)
304
305 slwi a, a, 16 // shift a
306 slwi b, b, 16 // shift b
307
308 lhz r5, 4(r6) // load ST
309
310 mflr r12 // save LR (we KNOW setst_add_32_laeco will not alter this register)
311
312 bl setst_add_32_laeco // perform addition and set flags
313
314 mtlr r12 // restore LR
315 srwi r3, r3, 16 // shift back result
316 sth r5, 4(r6) // save new ST
317 blr // and return
318 }
319
320 //
321 // Set laeco for subtract
322 //
setst_sub_laeco(register INT16 a,register INT16 b)323 static INT16 asm setst_sub_laeco(register INT16 a, register INT16 b)
324 {
325 // lwz r6, I(RTOC)
326 _asm_get_global(r6,I)
327
328 slwi a, a, 16
329 slwi b, b, 16
330
331 lhz r5, 4(r6)
332
333 mflr r12
334
335 bl setst_sub_32_laeco // perform substraction and set flags
336
337 mtlr r12
338 srwi r3, r3, 16
339 sth r5, 4(r6)
340 blr
341 }
342
343 //
344 // Set laecop for add (BYTE)
345 //
setst_addbyte_laecop(register INT8 a,register INT8 b)346 static INT8 asm setst_addbyte_laecop(register INT8 a, register INT8 b)
347 { // a -> r3, b -> r4
348 // lwz r6, I(RTOC)
349 _asm_get_global(r6,I)
350
351 slwi a, a, 24 // shift a
352 slwi b, b, 24 // shift b
353
354 lhz r5, 4(r6) // load ST
355
356 mflr r12 // save LR (we KNOW setst_add_32_laeco will not alter this register)
357
358 bl setst_add_32_laeco // perform addition and set flags
359
360 srwi r3, r3, 24 // shift back result
361 mtlr r12 // restore LR
362 sth r5, 4(r6) // save new ST
363 // stb r3, lastparity(RTOC) // copy result to lastparity
364 _asm_set_global_b(r3,lastparity) // copy result to lastparity
365 blr // and return
366 }
367
368 //
369 // Set laecop for subtract (BYTE)
370 //
setst_subbyte_laecop(register INT8 a,register INT8 b)371 static INT8 asm setst_subbyte_laecop(register INT8 a, register INT8 b)
372 { // a -> r3, b -> r4
373 // lwz r6, I(RTOC)
374 _asm_get_global(r6,I)
375
376 slwi a, a, 24
377 slwi b, b, 24
378
379 lhz r5, 4(r6)
380
381 mflr r12
382
383 bl setst_sub_32_laeco // perform substraction and set flags
384
385 srwi r3, r3, 24
386 mtlr r12
387 sth r5, 4(r6)
388 // stb r3, lastparity(RTOC)
389 _asm_set_global_b(r3,lastparity) // copy result to lastparity
390 blr
391 }
392
393 #else
394
395 /* Could do with some equivalent functions for non power PC's */
396
397 /*
398 Set laeco for add
399 */
setst_add_laeco(int a,int b)400 static INLINE INT16 setst_add_laeco(int a, int b)
401 {
402 UINT32 res;
403 INT16 res2;
404
405 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
406
407 res = (a & 0xffff) + (b & 0xffff);
408
409 if (res & 0x10000)
410 I.STATUS |= ST_C;
411
412 if ((res ^ b) & (res ^ a) & 0x8000)
413 I.STATUS |= ST_OV;
414
415 #if (TMS99XX_MODEL == TMS9940_ID)
416 if (((a & b) | ((a | b) & ~ res)) & 0x0800)
417 I.STATUS |= ST_DC;
418 #endif
419
420 res2 = (INT16) res;
421
422 if (res2 > 0)
423 I.STATUS |= ST_LGT | ST_AGT;
424 else if (res2 < 0)
425 I.STATUS |= ST_LGT;
426 else
427 I.STATUS |= ST_EQ;
428
429 return res2;
430 }
431
432
433 /*
434 Set laeco for subtract
435 */
setst_sub_laeco(int a,int b)436 static INLINE INT16 setst_sub_laeco(int a, int b)
437 {
438 UINT32 res;
439 INT16 res2;
440
441 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
442
443 res = (a & 0xffff) - (b & 0xffff);
444
445 if (! (res & 0x10000))
446 I.STATUS |= ST_C;
447
448 if ((a ^ b) & (a ^ res) & 0x8000)
449 I.STATUS |= ST_OV;
450
451 #if (TMS99XX_MODEL == TMS9940_ID)
452 if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x0800)
453 I.STATUS |= ST_DC;
454 #endif
455
456 res2 = (INT16) res;
457
458 if (res2 > 0)
459 I.STATUS |= ST_LGT | ST_AGT;
460 else if (res2 < 0)
461 I.STATUS |= ST_LGT;
462 else
463 I.STATUS |= ST_EQ;
464
465 return res2;
466 }
467
468
469 /*
470 Set laecop for add (BYTE)
471 */
setst_addbyte_laecop(int a,int b)472 static INLINE INT8 setst_addbyte_laecop(int a, int b)
473 {
474 unsigned int res;
475 INT8 res2;
476
477 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP);
478
479 res = (a & 0xff) + (b & 0xff);
480
481 if (res & 0x100)
482 I.STATUS |= ST_C;
483
484 if ((res ^ b) & (res ^ a) & 0x80)
485 I.STATUS |= ST_OV;
486
487 #if (TMS99XX_MODEL == TMS9940_ID)
488 if (((a & b) | ((a | b) & ~ res)) & 0x08)
489 I.STATUS |= ST_DC;
490 #endif
491
492 res2 = (INT8) res;
493
494 if (res2 > 0)
495 I.STATUS |= ST_LGT | ST_AGT;
496 else if (res2 < 0)
497 I.STATUS |= ST_LGT;
498 else
499 I.STATUS |= ST_EQ;
500
501 lastparity = res2;
502
503 return res2;
504 }
505
506
507 /*
508 Set laecop for subtract (BYTE)
509 */
setst_subbyte_laecop(int a,int b)510 static INLINE INT8 setst_subbyte_laecop(int a, int b)
511 {
512 unsigned int res;
513 INT8 res2;
514
515 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP);
516
517 res = (a & 0xff) - (b & 0xff);
518
519 if (! (res & 0x100))
520 I.STATUS |= ST_C;
521
522 if ((a ^ b) & (a ^ res) & 0x80)
523 I.STATUS |= ST_OV;
524
525 #if (TMS99XX_MODEL == TMS9940_ID)
526 if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x08)
527 I.STATUS |= ST_DC;
528 #endif
529
530 res2 = (INT8) res;
531
532 if (res2 > 0)
533 I.STATUS |= ST_LGT | ST_AGT;
534 else if (res2 < 0)
535 I.STATUS |= ST_LGT;
536 else
537 I.STATUS |= ST_EQ;
538
539 lastparity = res2;
540
541 return res2;
542 }
543
544 #endif
545
546
547
548 /*
549 For NEG
550 */
setst_laeo(INT16 val)551 static INLINE void setst_laeo(INT16 val)
552 {
553 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_OV);
554
555 if (val > 0)
556 I.STATUS |= ST_LGT | ST_AGT;
557 else if (val < 0)
558 {
559 I.STATUS |= ST_LGT;
560 if (((UINT16) val) == 0x8000)
561 I.STATUS |= ST_OV;
562 }
563 else
564 I.STATUS |= ST_EQ;
565 }
566
567
568
569 /*
570 Meat of SRA
571 */
setst_sra_laec(INT16 a,UINT16 c)572 static INLINE UINT16 setst_sra_laec(INT16 a, UINT16 c)
573 {
574 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C);
575
576 if (c != 0)
577 {
578 a = arithmetic_right_shift(a, c-1);
579 if (a & 1) // The carry bit equals the last bit that is shifted out
580 I.STATUS |= ST_C;
581 a = arithmetic_right_shift(a, 1);
582 }
583
584 if (a > 0)
585 I.STATUS |= ST_LGT | ST_AGT;
586 else if (a < 0)
587 I.STATUS |= ST_LGT;
588 else
589 I.STATUS |= ST_EQ;
590
591 return a;
592 }
593
594
595 /*
596 Meat of SRL. Same algorithm as SRA, except that we fills in with 0s.
597 */
setst_srl_laec(UINT16 a,UINT16 c)598 static INLINE UINT16 setst_srl_laec(UINT16 a,UINT16 c)
599 {
600 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C);
601
602 if (c != 0)
603 {
604 a = logical_right_shift(a, c-1);
605 if (a & 1)
606 I.STATUS |= ST_C;
607 a = logical_right_shift(a, 1);
608 }
609
610 if (((INT16) a) > 0)
611 I.STATUS |= ST_LGT | ST_AGT;
612 else if (((INT16) a) < 0)
613 I.STATUS |= ST_LGT;
614 else
615 I.STATUS |= ST_EQ;
616
617 return a;
618 }
619
620
621 //
622 // Meat of SRC
623 //
setst_src_laec(UINT16 a,UINT16 c)624 static INLINE UINT16 setst_src_laec(UINT16 a,UINT16 c)
625 {
626 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C);
627
628 if (c != 0)
629 {
630 a = logical_right_shift(a, c) | (a << (16-c));
631 if (a & 0x8000) // The carry bit equals the last bit that is shifted out
632 I.STATUS |= ST_C;
633 }
634
635 if (((INT16) a) > 0)
636 I.STATUS |= ST_LGT | ST_AGT;
637 else if (((INT16) a) < 0)
638 I.STATUS |= ST_LGT;
639 else
640 I.STATUS |= ST_EQ;
641
642 return a;
643 }
644
645
646 //
647 // Meat of SLA
648 //
setst_sla_laeco(UINT16 a,UINT16 c)649 static INLINE UINT16 setst_sla_laeco(UINT16 a, UINT16 c)
650 {
651 I.STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV);
652
653 if (c != 0)
654 {
655 {
656 register UINT16 mask;
657 register UINT16 ousted_bits;
658
659 mask = 0xFFFF << (16-c-1);
660 ousted_bits = a & mask;
661
662 if (ousted_bits) // If ousted_bits is neither all 0s
663 if (ousted_bits ^ mask) // nor all 1s,
664 I.STATUS |= ST_OV; // we set overflow
665 }
666
667 a <<= c-1;
668 if (a & 0x8000) // The carry bit equals the last bit that is shifted out
669 I.STATUS |= ST_C;
670
671 a <<= 1;
672 }
673
674 if (((INT16) a) > 0)
675 I.STATUS |= ST_LGT | ST_AGT;
676 else if (((INT16) a) < 0)
677 I.STATUS |= ST_LGT;
678 else
679 I.STATUS |= ST_EQ;
680
681 return a;
682 }
683
684
685 /***********************************************************************/
686
687