diff options
Diffstat (limited to 'sim/mips/vr.igen')
-rw-r--r-- | sim/mips/vr.igen | 321 |
1 files changed, 283 insertions, 38 deletions
diff --git a/sim/mips/vr.igen b/sim/mips/vr.igen index 863bb55..0eb5f4d 100644 --- a/sim/mips/vr.igen +++ b/sim/mips/vr.igen @@ -3,76 +3,321 @@ // NEC specific instructions // -// Integer Instructions -// -------------------- -// -// MulAcc is the Multiply Accumulator. -// This register is mapped on the the HI and LO registers. -// Upper 32 bits of MulAcc is mapped on to lower 32 bits of HI register. -// Lower 32 bits of MulAcc is mapped on to lower 32 bits of LO register. +:%s::::MFHI:int hi +{ + return hi ? "hi" : ""; +} +:%s::::SAT:int s +{ + return s ? "s" : ""; +} -:function:::unsigned64:MulAcc: -*vr4100: +:%s::::UNS:int u { - unsigned64 result = U8_4 (HI, LO); - return result; + return u ? "u" : ""; } -:function:::void:SET_MulAcc:unsigned64 value -*vr4100: +// Simulate the various kinds of multiply and multiply-accumulate instructions. +// Perform an operation of the form: +// +// LHS (+/-) GPR[RS] * GPR[RT] +// +// and store it in the 64-bit accumulator. Optionally copy either LO or +// HI into a general purpose register. +// +// - RD is the destination register of the LO or HI move +// - RS are RT are the multiplication source registers +// - ACCUMULATE_P is true if LHS should be the value of the 64-bit accumulator, +// false if it should be 0. +// - STORE_HI_P is true if HI should be stored in RD, false if LO should be. +// - UNSIGNED_P is true if the operation should be unsigned. +// - SATURATE_P is true if the result should be saturated to a 32-bit value. +// - SUBTRACT_P is true if the right hand side should be subtraced from LHS, +// false if it should be added. +// - SHORT_P is true if RS and RT must be 16-bit numbers. +// - DOUBLE_P is true if the 64-bit accumulator is in LO, false it is a +// concatenation of the low 32 bits of HI and LO. +:function:::void:do_vr_mul_op:int rd, int rs, int rt, int accumulate_p, int store_hi_p, int unsigned_p, int saturate_p, int subtract_p, int short_p, int double_p { - /* 64 bit specific */ - *AL4_8 (&HI) = VH4_8 (value); - *AL4_8 (&LO) = VL4_8 (value); + unsigned64 lhs, x, y, xcut, ycut, product, result; + + check_mult_hilo (SD_, HIHISTORY, LOHISTORY); + + lhs = (!accumulate_p ? 0 : double_p ? LO : U8_4 (HI, LO)); + x = GPR[rs]; + y = GPR[rt]; + + /* Work out the canonical form of X and Y from their significant bits. */ + if (!short_p) + { + /* Normal sign-extension rule for 32-bit operands. */ + xcut = EXTEND32 (x); + ycut = EXTEND32 (y); + } + else if (unsigned_p) + { + /* Operands must be zero-extended 16-bit numbers. */ + xcut = x & 0xffff; + ycut = y & 0xffff; + } + else + { + /* Likewise but sign-extended. */ + xcut = EXTEND16 (x); + ycut = EXTEND16 (y); + } + if (x != xcut || y != ycut) + sim_engine_abort (SD, CPU, CIA, + "invalid multiplication operand at 0x%08lx\n", + (long) CIA); + + TRACE_ALU_INPUT2 (x, y); + product = (unsigned_p ? x * y : EXTEND32 (x) * EXTEND32 (y)); + result = (subtract_p ? lhs - product : lhs + product); + if (saturate_p) + { + /* Saturate the result to 32 bits. An unsigned, unsaturated + result is zero-extended to 64 bits, but unsigned overflow + causes all 64 bits to be set. */ + if (!unsigned_p && (unsigned64) EXTEND32 (result) != result) + result = ((signed64) result < 0 ? -0x7fffffff - 1 : 0x7fffffff); + else if (unsigned_p && (result >> 32) != 0) + result = (unsigned64) 0 - 1; + } + TRACE_ALU_RESULT (result); + + if (double_p) + LO = result; + else + { + LO = EXTEND32 (result); + HI = EXTEND32 (VH4_8 (result)); + } + if (rd != 0) + GPR[rd] = store_hi_p ? HI : LO; } -:function:::signed64:SignedMultiply:signed32 l, signed32 r -*vr4100: +// 32-bit rotate right of X by Y bits. +:function:::unsigned64:do_ror:unsigned32 x,unsigned32 y +*vr5400: +*vr5500: { - signed64 result = (signed64) l * (signed64) r; + unsigned64 result; + + y &= 31; + TRACE_ALU_INPUT2 (x, y); + result = EXTEND32 (ROTR32 (x, y)); + TRACE_ALU_RESULT (result); return result; } -:function:::unsigned64:UnsignedMultiply:unsigned32 l, unsigned32 r -*vr4100: +// Likewise 64-bit +:function:::unsigned64:do_dror:unsigned64 x,unsigned64 y +*vr5400: +*vr5500: { - unsigned64 result = (unsigned64) l * (unsigned64) r; + unsigned64 result; + + y &= 63; + TRACE_ALU_INPUT2 (x, y); + result = ROTR64 (x, y); + TRACE_ALU_RESULT (result); return result; } -:function:::unsigned64:Low32Bits:unsigned64 value + +// VR4100 instructions. + +000000,5.RS,5.RT,00000,00000,101000::32::MADD16 +"madd16 r<RS>, r<RT>" *vr4100: { - unsigned64 result = (signed64) (signed32) VL4_8 (value); - return result; + do_vr_mul_op (SD_, 0, RS, RT, + 1 /* accumulate */, + 0 /* store in LO */, + 0 /* signed arithmetic */, + 0 /* don't saturate */, + 0 /* don't subtract */, + 1 /* short */, + 0 /* single */); } -:function:::unsigned64:High32Bits:unsigned64 value +000000,5.RS,5.RT,00000,00000,101001::64::DMADD16 +"dmadd16 r<RS>, r<RT>" *vr4100: { - unsigned64 result = (signed64) (signed32) VH4_8 (value); - return result; + do_vr_mul_op (SD_, 0, RS, RT, + 1 /* accumulate */, + 0 /* store in LO */, + 0 /* signed arithmetic */, + 0 /* don't saturate */, + 0 /* don't subtract */, + 1 /* short */, + 1 /* double */); } -// Multiply, Accumulate -000000,5.RS,5.RT,00000,00000,101000::64::MAC -"mac r<RS>, r<RT>" -*vr4100: +// VR4120 and VR4130 instructions. + +000000,5.RS,5.RT,5.RD,1.SAT,1.MFHI,00,1.UNS,101001::64::DMACC +"dmacc%s<MFHI>%s<UNS>%s<SAT> r<RD>, r<RS>, r<RT>" +*vr4120: { - SET_MulAcc (SD_, MulAcc (SD_) + SignedMultiply (SD_, GPR[RS], GPR[RT])); + do_vr_mul_op (SD_, RD, RS, RT, + 1 /* accumulate */, + MFHI, UNS, SAT, + 0 /* don't subtract */, + SAT /* short */, + 1 /* double */); } +000000,5.RS,5.RT,5.RD,1.SAT,1.MFHI,00,1.UNS,101000::32::MACC_4120 +"macc%s<MFHI>%s<UNS>%s<SAT> r<RD>, r<RS>, r<RT>" +*vr4120: +{ + do_vr_mul_op (SD_, RD, RS, RT, + 1 /* accumulate */, + MFHI, UNS, SAT, + 0 /* don't subtract */, + SAT /* short */, + 0 /* single */); +} -// D-Multiply, Accumulate -000000,5.RS,5.RT,00000,00000,101001::64::DMAC -"dmac r<RS>, r<RT>" -*vr4100: + +// VR5400 and VR5500 instructions. + +000000,5.RS,5.RT,5.RD,0,1.MFHI,001,01100,1.UNS::32::MUL +"mul%s<MFHI>%s<UNS> r<RD>, r<RS>, r<RT>" +*vr5400: +*vr5500: { - LO = LO + SignedMultiply (SD_, GPR[RS], GPR[RT]); + do_vr_mul_op (SD_, RD, RS, RT, + 0 /* don't accumulate */, + MFHI, UNS, + 0 /* don't saturate */, + 0 /* don't subtract */, + 0 /* not short */, + 0 /* single */); } +000000,5.RS,5.RT,5.RD,0,1.MFHI,011,01100,1.UNS::32::MULS +"muls%s<MFHI>%s<UNS> r<RD>, r<RS>, r<RT>" +*vr5400: +*vr5500: +{ + do_vr_mul_op (SD_, RD, RS, RT, + 0 /* don't accumulate */, + MFHI, UNS, + 0 /* don't saturate */, + 1 /* subtract */, + 0 /* not short */, + 0 /* single */); +} + +000000,5.RS,5.RT,5.RD,0,1.MFHI,101,01100,1.UNS::32::MACC_5xxx +"macc%s<MFHI>%s<UNS> r<RD>, r<RS>, r<RT>" +*vr5400: +*vr5500: +{ + do_vr_mul_op (SD_, RD, RS, RT, + 1 /* accumulate */, + MFHI, UNS, + 0 /* don't saturate */, + 0 /* don't subtract */, + 0 /* not short */, + 0 /* single */); +} + +000000,5.RS,5.RT,5.RD,0,1.MFHI,111,01100,1.UNS::32::MSAC +"msac%s<MFHI>%s<UNS> r<RD>, r<RS>, r<RT>" +*vr5400: +*vr5500: +{ + do_vr_mul_op (SD_, RD, RS, RT, + 1 /* accumulate */, + MFHI, UNS, + 0 /* don't saturate */, + 1 /* subtract */, + 0 /* not short */, + 0 /* single */); +} + +000000,00001,5.RT,5.RD,5.SHIFT,000010::32::ROR +"ror r<RD>, r<RT>, <SHIFT>" +*vr5400: +*vr5500: +{ + GPR[RD] = do_ror (SD_, GPR[RT], SHIFT); +} + +000000,5.RS,5.RT,5.RD,00001,000110::32::RORV +"rorv r<RD>, r<RT>, r<RS>" +*vr5400: +*vr5500: +{ + GPR[RD] = do_ror (SD_, GPR[RT], GPR[RS]); +} + +000000,00001,5.RT,5.RD,5.SHIFT,111010::64::DROR +"dror r<RD>, r<RT>, <SHIFT>" +*vr5400: +*vr5500: +{ + GPR[RD] = do_dror (SD_, GPR[RT], SHIFT); +} + +000000,00001,5.RT,5.RD,5.SHIFT,111110::64::DROR32 +"dror32 r<RD>, r<RT>, <SHIFT>" +*vr5400: +*vr5500: +{ + GPR[RD] = do_dror (SD_, GPR[RT], SHIFT + 32); +} + +000000,5.RS,5.RT,5.RD,00001,010110::64::DRORV +"drorv r<RD>, r<RT>, r<RS>" +*vr5400: +*vr5500: +{ + GPR[RD] = do_dror (SD_, GPR[RT], GPR[RS]); +} + +010011,5.BASE,5.INDEX,5.0,5.FD,000101:COP1X:64::LUXC1 +"luxc1 f<FD>, r<INDEX>(r<BASE>)" +*vr5500: +{ + check_fpu (SD_); + COP_LD (1, FD, do_load (SD_, AccessLength_DOUBLEWORD, + (GPR[BASE] + GPR[INDEX]) & ~MASK64 (2, 0), 0)); +} + +010011,5.BASE,5.INDEX,5.FS,00000,001101:COP1X:64::SUXC1 +"suxc1 f<FS>, r<INDEX>(r<BASE>)" +*vr5500: +{ + check_fpu (SD_); + do_store (SD_, AccessLength_DOUBLEWORD, + (GPR[BASE] + GPR[INDEX]) & ~MASK64 (2, 0), 0, + COP_SD (1, FS)); +} + +010000,1,19.*,100000:COP0:32::WAIT +"wait" +*vr5500: + +011100,00000,5.RT,5.DR,00000,111101:SPECIAL:64::MFDR +"mfdr r<RT>, r<DR>" +*vr5400: +*vr5500: +011100,00100,5.RT,5.DR,00000,111101:SPECIAL:64::MTDR +"mtdr r<RT>, r<DR>" +*vr5400: +*vr5500: +011100,00000,00000,00000,00000,111110:SPECIAL:64::DRET +"dret" +*vr5400: +*vr5500: |