/* Status word functions */ #include "centry.h" extern s16 lastcmp, lastval; extern u8 st_o, st_c, st_p; /************************************************************************/ u16 statusto9900(void); void T9900tostatus(u16 stat); #ifdef __9900__ /* Set lae, preserve C and O */ s16 INLINE setst_lae(s16 val) { lastcmp=0; lastval=val; return val; } /* Set lae, preserve C and O (BYTE) */ s8 INLINE setst_byte_laep(s8 val) { #if defined(GNU_X86_ASM) || defined(FAST_X86_STATUS) status &= ~ST_P; asm( "\t or %0,%0\n" "\t jpe 1f\n" "\t orb $0x4,status+1\n" "\t1:\n" : : "r" (val) ); lastval=val; lastcmp=0; return val; #else #if 0 /* Parity checking using XOR. Logic: 0^0 == 0 (even # one bits) 1^1 == 0 (even # one bits) 1^0 == 1 0^1 == 1 (odd # one bits) Just XOR the bits over each other until we have one bit representing the parity. */ u8 a,b,c; a = ((val & 0xaa) >> 1) ^ (val & 0x55); /* a = 0?0?0?0? */ b = ((a & 0x44) >> 2) ^ (a & 0x11); /* b = 000?000? */ c = ((b & 0x20) >> 4) ^ (a & 0x2); /* c = 0000000? */ #elif 0 /* Perhaps we don't need all the ands if we shift it all to the end. */ u8 a,b,c; a = (val >> 4) ^ val; b = (a >> 2) ^ a; c = (b >> 1) ^ b; c &= 1; #elif 0 /* halve the work. it's easy to set up an array of parity bits for the nybbles 0 through 15. */ static u8 parity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}; u8 c; c = (parity[(val & 0xf)] ^ parity[(val >> 4)]) & 1; #elif 1 /* notice the bitmap formed by the parity[] array above == 0x6996 */ u8 c; /* uhoh -- this is functionally equivalent to a "copyrighted" algorithm by Tom Brouwer in ti4linux, but I derived it myself. */ #define PARITY(b) \ (( (0x6996 >> ((b) & 0xf) ) ^ \ (0x6996 >> (((b) >> 4) & 0xf) )) & 1) c = PARITY(val); #endif #if defined(GNU_X86_ASM) || defined(FAST_X86_STATUS) if (c) status |= ST_P; /* odd parity */ else status &= ~ST_P; #else st_p = c; #endif lastval=val; lastcmp=0; return val; #endif } /* For COC, CZC, and TB */ void INLINE setst_e(u16 val,u16 to) { if (val==to){ lastcmp=lastval=0; } else { if (lastcmp==lastval) lastval++; } } #if defined(FAST_X86_STATUS) #define I86_CF 1 #define I86_OF (1<<11) #define I86_PF (1<<2) u8 i86_to_9900[I86_OF+I86_CF+I86_PF+1]; /* One-time setup of i86_to_9900 array. For each entry corresponding to some combination of bits set in the x86 status flag, we set the corresponding entry to the 9900 status flag value. */ void setup_status(void) { int i; memset(i86_to_9900,0x00,sizeof(i86_to_9900)); for (i=0; i carry #elif !defined(FAST_X86_STATUS) register u16 res=dst; status&=~(ST_C|ST_O); asm( "\t negw %0\n" "\t jnz 3f\n" "\t orb $0x10,status+1\n" "3:\t addw %1,%0\n" "\t pushf\n" "\t jno 1f\n" "\t orb $0x8,status+1\n" "\t1: popf\n" "\t jnc 2f\n" "\t orb $0x10,status+1\n" "\t2:\n" : "=r" (res) : "g" (dst), "0" (src) ); #else // FAST_X86_STATUS register u16 res=dst; register u32 flags; register u8 tmp; status&=~(ST_C|ST_O); asm( "\t negw %0\n" "\t jnz 3f\n" "\t orb $0x10,status+1\n" "3:\t addw %1,%0\n" "\t pushf\n" "\t popl %3\n" "\t andl $2049,%3\n" "\t movb i86_to_9900(%3),%4\n" "\t orb %4,status+1\n" : "=r" (res) : "g" (dst), "0" (src), "r" (flags), "r" (tmp) ); #endif lastval=res; lastcmp=0; return res; } /* Set laeco for add, preserve none (BYTE) */ s8 INLINE setst_addbyte_laecop(s8 dst,s8 src) { #if !defined(GNU_X86_ASM) && !defined(FAST_X86_STATUS) s8 res = dst + src; st_c = (((dst & src) & 0x80) || (((dst & 0x80) ^ (src & 0x80)) && !(res & 0x80))) != 0; st_o = (((~dst & ~src & res) | (dst & src & ~res)) & 0x80) != 0; st_p = (PARITY(res)); #elif !defined(FAST_X86_STATUS) register s8 res=dst; status&=~(ST_C|ST_O|ST_P); asm( "\t addb %1,%0\n" "\t pushf\n" "\t jno 1f\n" "\t orb $0x8,status+1\n" "\t1: popf\n" "\t pushf\n" "\t jnc 2f\n" "\t orb $0x10,status+1\n" "\t2:\n" "\t popf\n" "\t jpe 3f\n" "\t orb $0x4,status+1\n" "\t3:\n" : "=r" (res) : "g" (src), "0" (dst) ); #else // FAST_X86_STATUS register s8 res=dst; register u32 flags; register u8 tmp; status&=~(ST_C|ST_O|ST_P); asm( "\t addb %1,%0\n" "\t pushf\n" "\t popl %3\n" "\t andl $2053,%3\n" "\t movb i86_to_9900(%3),%4\n" "\t orb %4,status+1\n" : "=r" (res) : "g" (src), "0" (dst), "r" (flags), "r" (tmp) ); #endif lastval=(s16)res; lastcmp=0; return res; } /* Set laeco for subtract, preserve none (BYTE) */ s8 INLINE setst_subbyte_laecop(s8 dst,s8 src) { #if !defined(GNU_X86_ASM) && !defined(FAST_X86_STATUS) s8 res = setst_addbyte_laecop(dst, 1+~src); st_c |= (src==0 || (u8)src==0x80); // the inverse + increment ==> carry #elif !defined(FAST_X86_STATUS) register s8 res=dst; register u32 flags; register u8 tmp; status&=~(ST_C|ST_O|ST_P); asm( "\t negb %0\n" "\t jnz 3f\n" "\t orb $0x10,status+1\n" "\t3:\t addb %1,%0\n" "\t pushf\n" "\t jno 1f\n" "\t orb $0x8,status+1\n" "\t1: popf\n" "\t pushf\n" "\t jnc 2f\n" "\t orb $0x10,status+1\n" "\t2:\n" "\t popf\n" "\t jpe 3f\n" "\t orb $0x4,status+1\n" "\t3:\n" : "=rb" (res) : "g" (dst), "0" (src) ); #else // FAST_X86_STATUS register s8 res=dst; register u32 flags; register u8 tmp; status&=~(ST_C|ST_O|ST_P); asm( "\t negb %0\n" "\t jnz 3f\n" "\t orb $0x10,status+1\n" "3:\t addb %1,%0\n" "\t pushf\n" "\t popl %3\n" "\t andl $2053,%3\n" "\t movb i86_to_9900(%3),%4\n" "\t orb %4,status+1\n" : "=r" (res) : "g" (dst), "0" (src), "r" (flags), "r" (tmp) ); #endif lastval=(s16)res; lastcmp=0; return res; } /* For ABS */ u16 INLINE setst_o(u16 val) { #if defined(GNU_X86_ASM) || defined(FAST_X86_STATUS) status = (status & ~ST_O) | ((val == 0x8000) ? ST_O : 0); #else st_o = (val==0x8000); #endif return val; } /* For NEG */ u16 INLINE setst_laeo(u16 val) { setst_o(val); lastval=val; lastcmp=0; return val; } #endif /************************************************************************/ #include "cexit.h"