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