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