diff options
Diffstat (limited to 'trunk/src/emu/cpu/tms9900/99xxstat.h')
-rw-r--r-- | trunk/src/emu/cpu/tms9900/99xxstat.h | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/tms9900/99xxstat.h b/trunk/src/emu/cpu/tms9900/99xxstat.h new file mode 100644 index 00000000000..bde84b39928 --- /dev/null +++ b/trunk/src/emu/cpu/tms9900/99xxstat.h @@ -0,0 +1,483 @@ +/************************************************************************ + + ST register functions + +************************************************************************/ + +/* + remember that the OP ST bit is maintained in cpustate->lastparity +*/ + +/* + setstat sets the ST_OP bit according to cpustate->lastparity + + It must be called before reading the ST register. +*/ + +static void setstat(tms99xx_state *cpustate) +{ + int i; + UINT8 a; + + cpustate->STATUS &= ~ ST_OP; + + /* We set the parity bit. */ + a = cpustate->lastparity; + + for (i=0; i<8; i++) /* 8 bits to test */ + { + if (a & 1) /* If current bit is set */ + cpustate->STATUS ^= ST_OP; /* we toggle the ST_OP bit */ + + a >>= 1; /* Next bit. */ + } +} + +/* + getstat sets emulator's cpustate->lastparity variable according to 9900's STATUS bits. + It must be called on interrupt return, or when, for some reason, + the emulated program sets the STATUS register directly. +*/ +static void getstat(tms99xx_state *cpustate) +{ +#if (USE_ST_MASK) + cpustate->STATUS &= ST_MASK; /* unused bits are forced to 0 */ +#endif + + if (cpustate->STATUS & ST_OP) + cpustate->lastparity = 1; + else + cpustate->lastparity = 0; + +#if HAS_MAPPING + cpustate->cur_map = (cpustate->STATUS & ST_MF) ? 1 : 0; +#endif +} + +/* + A few words about the following functions. + + A big portability issue is the behavior of the ">>" instruction with the sign bit, which has + not been normalised. Every compiler does whatever it thinks smartest. + My code assumed that when shifting right signed numbers, the operand is left-filled with a + copy of sign bit, and that when shifting unsigned variables, it is left-filled with 0s. + This is probably the most logical behaviour, and it is the behavior of CW PRO3 - most time + (the exception is that ">>=" instructions always copy the sign bit (!)). But some compilers + are bound to disagree. + + So, I had to create special functions with predefined tables included, so that this code work + on every compiler. BUT this is a real slow-down. + So, you might have to include a few lines in assembly to make this work better. + Sorry about this, this problem is really unpleasant and absurd, but it is not my fault. +*/ + + +static const UINT16 right_shift_mask_table[17] = +{ + 0xFFFF, + 0x7FFF, + 0x3FFF, + 0x1FFF, + 0x0FFF, + 0x07FF, + 0x03FF, + 0x01FF, + 0x00FF, + 0x007F, + 0x003F, + 0x001F, + 0x000F, + 0x0007, + 0x0003, + 0x0001, + 0x0000 +}; + +static const UINT16 inverted_right_shift_mask_table[17] = +{ + 0x0000, + 0x8000, + 0xC000, + 0xE000, + 0xF000, + 0xF800, + 0xFC00, + 0xFE00, + 0xFF00, + 0xFF80, + 0xFFC0, + 0xFFE0, + 0xFFF0, + 0xFFF8, + 0xFFFC, + 0xFFFE, + 0xFFFF +}; + +INLINE UINT16 logical_right_shift(UINT16 val, int c) +{ + return((val>>c) & right_shift_mask_table[c]); +} + +INLINE INT16 arithmetic_right_shift(INT16 val, int c) +{ + if (val < 0) + return((val>>c) | inverted_right_shift_mask_table[c]); + else + return((val>>c) & right_shift_mask_table[c]); +} + + + + + +/* + Set lae +*/ +INLINE void setst_lae(tms99xx_state *cpustate, INT16 val) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ); + + if (val > 0) + cpustate->STATUS |= (ST_LGT | ST_AGT); + else if (val < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; +} + + +/* + Set laep (BYTE) +*/ +INLINE void setst_byte_laep(tms99xx_state *cpustate, INT8 val) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ); + + if (val > 0) + cpustate->STATUS |= (ST_LGT | ST_AGT); + else if (val < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + cpustate->lastparity = val; +} + +/* + For COC, CZC, and TB +*/ +INLINE void setst_e(tms99xx_state *cpustate, UINT16 val, UINT16 to) +{ + if (val == to) + cpustate->STATUS |= ST_EQ; + else + cpustate->STATUS &= ~ ST_EQ; +} + +/* + For CI, C, CB +*/ +INLINE void setst_c_lae(tms99xx_state *cpustate, UINT16 to, UINT16 val) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ); + + if (val == to) + cpustate->STATUS |= ST_EQ; + else + { + if ( ((INT16) val) > ((INT16) to) ) + cpustate->STATUS |= ST_AGT; + if ( ((UINT16) val) > ((UINT16) to) ) + cpustate->STATUS |= ST_LGT; + } +} + +/* + Set laeco for add +*/ +INLINE INT16 setst_add_laeco(tms99xx_state *cpustate, int a, int b) +{ + UINT32 res; + INT16 res2; + + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); + + res = (a & 0xffff) + (b & 0xffff); + + if (res & 0x10000) + cpustate->STATUS |= ST_C; + + if ((res ^ b) & (res ^ a) & 0x8000) + cpustate->STATUS |= ST_OV; + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + if (((a & b) | ((a | b) & ~ res)) & 0x0800) + cpustate->STATUS |= ST_DC; +#endif + + res2 = (INT16) res; + + if (res2 > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (res2 < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return res2; +} + + +/* + Set laeco for subtract +*/ +INLINE INT16 setst_sub_laeco(tms99xx_state *cpustate, int a, int b) +{ + UINT32 res; + INT16 res2; + + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); + + res = (a & 0xffff) - (b & 0xffff); + + if (! (res & 0x10000)) + cpustate->STATUS |= ST_C; + + if ((a ^ b) & (a ^ res) & 0x8000) + cpustate->STATUS |= ST_OV; + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x0800) + cpustate->STATUS |= ST_DC; +#endif + + res2 = (INT16) res; + + if (res2 > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (res2 < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return res2; +} + + +/* + Set laecop for add (BYTE) +*/ +INLINE INT8 setst_addbyte_laecop(tms99xx_state *cpustate, int a, int b) +{ + unsigned int res; + INT8 res2; + + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP); + + res = (a & 0xff) + (b & 0xff); + + if (res & 0x100) + cpustate->STATUS |= ST_C; + + if ((res ^ b) & (res ^ a) & 0x80) + cpustate->STATUS |= ST_OV; + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + if (((a & b) | ((a | b) & ~ res)) & 0x08) + cpustate->STATUS |= ST_DC; +#endif + + res2 = (INT8) res; + + if (res2 > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (res2 < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + cpustate->lastparity = res2; + + return res2; +} + + +/* + Set laecop for subtract (BYTE) +*/ +INLINE INT8 setst_subbyte_laecop(tms99xx_state *cpustate, int a, int b) +{ + unsigned int res; + INT8 res2; + + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV | ST_OP); + + res = (a & 0xff) - (b & 0xff); + + if (! (res & 0x100)) + cpustate->STATUS |= ST_C; + + if ((a ^ b) & (a ^ res) & 0x80) + cpustate->STATUS |= ST_OV; + +#if (TMS99XX_MODEL == TMS9940_ID) || (TMS99XX_MODEL == TMS9985_ID) + if (((a & ~ b) | ((a | ~ b) & ~ res)) & 0x08) + cpustate->STATUS |= ST_DC; +#endif + + res2 = (INT8) res; + + if (res2 > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (res2 < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + cpustate->lastparity = res2; + + return res2; +} + + + +/* + For NEG +*/ +INLINE void setst_laeo(tms99xx_state *cpustate, INT16 val) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_OV); + + if (val > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (val < 0) + { + cpustate->STATUS |= ST_LGT; + if (((UINT16) val) == 0x8000) + cpustate->STATUS |= ST_OV; + } + else + cpustate->STATUS |= ST_EQ; +} + + + +/* + Meat of SRA +*/ +INLINE UINT16 setst_sra_laec(tms99xx_state *cpustate, INT16 a, UINT16 c) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C); + + if (c != 0) + { + a = arithmetic_right_shift(a, c-1); + if (a & 1) // The carry bit equals the last bit that is shifted out + cpustate->STATUS |= ST_C; + a = arithmetic_right_shift(a, 1); + } + + if (a > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (a < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return a; +} + + +/* + Meat of SRL. Same algorithm as SRA, except that we fills in with 0s. +*/ +INLINE UINT16 setst_srl_laec(tms99xx_state *cpustate, UINT16 a,UINT16 c) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C); + + if (c != 0) + { + a = logical_right_shift(a, c-1); + if (a & 1) + cpustate->STATUS |= ST_C; + a = logical_right_shift(a, 1); + } + + if (((INT16) a) > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (((INT16) a) < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return a; +} + + +// +// Meat of SRC +// +INLINE UINT16 setst_src_laec(tms99xx_state *cpustate, UINT16 a,UINT16 c) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C); + + if (c != 0) + { + a = logical_right_shift(a, c) | (a << (16-c)); + if (a & 0x8000) // The carry bit equals the last bit that is shifted out + cpustate->STATUS |= ST_C; + } + + if (((INT16) a) > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (((INT16) a) < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return a; +} + + +// +// Meat of SLA +// +INLINE UINT16 setst_sla_laeco(tms99xx_state *cpustate, UINT16 a, UINT16 c) +{ + cpustate->STATUS &= ~ (ST_LGT | ST_AGT | ST_EQ | ST_C | ST_OV); + + if (c != 0) + { + { + register UINT16 mask; + register UINT16 ousted_bits; + + mask = 0xFFFF << (16-c-1); + ousted_bits = a & mask; + + if (ousted_bits) // If ousted_bits is neither all 0s + if (ousted_bits ^ mask) // nor all 1s, + cpustate->STATUS |= ST_OV; // we set overflow + } + + a <<= c-1; + if (a & 0x8000) // The carry bit equals the last bit that is shifted out + cpustate->STATUS |= ST_C; + + a <<= 1; + } + + if (((INT16) a) > 0) + cpustate->STATUS |= ST_LGT | ST_AGT; + else if (((INT16) a) < 0) + cpustate->STATUS |= ST_LGT; + else + cpustate->STATUS |= ST_EQ; + + return a; +} + + +/***********************************************************************/ + |