Path: blob/master/libsnes/bsnes/snes/chip/armdsp/opcodes.cpp
2 views
#ifdef ARMDSP_CPP12bool ArmDSP::condition() {3uint4 condition = instruction >> 28;4switch(condition) {5case 0: return cpsr.z == 1; //EQ (equal)6case 1: return cpsr.z == 0; //NE (not equal)7case 2: return cpsr.c == 1; //CS (carry set)8case 3: return cpsr.c == 0; //CC (carry clear)9case 4: return cpsr.n == 1; //MI (negative)10case 5: return cpsr.n == 0; //PL (positive)11case 6: return cpsr.v == 1; //VS (overflow)12case 7: return cpsr.v == 0; //VC (no overflow)13case 8: return cpsr.c == 1 && cpsr.z == 0; //HI (unsigned higher)14case 9: return cpsr.c == 0 || cpsr.z == 1; //LS (unsigned lower or same)15case 10: return cpsr.n == cpsr.v; //GE (signed greater than or equal)16case 11: return cpsr.n != cpsr.v; //LT (signed less than)17case 12: return cpsr.z == 0 && cpsr.n == cpsr.v; //GT (signed greater than)18case 13: return cpsr.z == 1 || cpsr.n != cpsr.v; //LE (signed less than or equal)19case 14: return true; //AL (always)20case 15: return false; //NV (never)21}22}2324//rd = target25//rn = source26//rm = modifier27//ri = original target28//ro = modified target29void ArmDSP::opcode(uint32 rm) {30uint4 opcode = instruction >> 21;31uint1 save = instruction >> 20;32uint4 n = instruction >> 16;33uint4 d = instruction >> 12;3435uint32 rn = r[n];3637//comparison opcodes always update flags (debug test)38//this can be removed later: s=0 opcode=8-11 is invalid39if(opcode >= 8 && opcode <= 11) assert(save == 1);4041auto test = [&](uint32 result) {42if(save) {43cpsr.n = result >> 31;44cpsr.z = result == 0;45cpsr.c = shiftercarry;46}47return result;48};4950auto math = [&](uint32 source, uint32 modify, bool carry) {51uint32 result = source + modify + carry;52if(save) {53uint32 overflow = ~(source ^ modify) & (source ^ result);54cpsr.n = result >> 31;55cpsr.z = result == 0;56cpsr.c = (1u << 31) & (overflow ^ source ^ modify ^ result);57cpsr.v = (1u << 31) & (overflow);58}59return result;60};6162switch(opcode) {63case 0: r[d] = test(rn & rm); break; //AND64case 1: r[d] = test(rn ^ rm); break; //EOR65case 2: r[d] = math(rn, ~rm, 1); break; //SUB66case 3: r[d] = math(rm, ~rn, 1); break; //RSB67case 4: r[d] = math(rn, rm, 0); break; //ADD68case 5: r[d] = math(rn, rm, cpsr.c); break; //ADC69case 6: r[d] = math(rn, ~rm, cpsr.c); break; //SBC70case 7: r[d] = math(rm, ~rn, cpsr.c); break; //RSC71case 8: test(rn & rm); break; //TST72case 9: test(rn ^ rm); break; //TEQ73case 10: math(rn, ~rm, 1); break; //CMP74case 11: math(rn, rm, 0); break; //CMN75case 12: r[d] = test(rn | rm); break; //ORR76case 13: r[d] = test(rm); break; //MOV77case 14: r[d] = test(rn &~rm); break; //BIC78case 15: r[d] = test(~rm); break; //MVN79}80}8182//logical shift left83void ArmDSP::lsl(bool &c, uint32 &rm, uint32 rs) {84while(rs--) {85c = rm >> 31;86rm <<= 1;87}88}8990//logical shift right91void ArmDSP::lsr(bool &c, uint32 &rm, uint32 rs) {92while(rs--) {93c = rm & 1;94rm >>= 1;95}96}9798//arithmetic shift right99void ArmDSP::asr(bool &c, uint32 &rm, uint32 rs) {100while(rs--) {101c = rm & 1;102rm = (int32)rm >> 1;103}104}105106//rotate right107void ArmDSP::ror(bool &c, uint32 &rm, uint32 rs) {108while(rs--) {109c = rm & 1;110rm = (rm << 31) | (rm >> 1);111}112}113114//rotate right with extend115void ArmDSP::rrx(bool &c, uint32 &rm) {116bool carry = c;117c = rm & 1;118rm = (carry << 31) | (rm >> 1);119}120121//(mul,mla){condition}{s} rd,rm,rs,rn122//cccc 0000 00as dddd nnnn ssss 1001 mmmm123//c = condition124//a = accumulate125//s = save flags126//d = rd127//n = rn128//s = rs129//n = rm130void ArmDSP::op_multiply() {131uint1 accumulate = instruction >> 21;132uint1 save = instruction >> 20;133uint4 d = instruction >> 16;134uint4 n = instruction >> 12;135uint4 s = instruction >> 8;136uint4 m = instruction >> 0;137138//Booth's algorithm: two bit steps139uint32 temp = r[s];140while(temp) {141temp >>= 2;142tick();143}144r[d] = r[m] * r[s];145146if(accumulate) {147tick();148r[d] += r[n];149}150151if(save) {152cpsr.n = r[d] >> 31;153cpsr.z = r[d] == 0;154cpsr.c = 0; //undefined155}156}157158//mrs{condition} rd,(c,s)psr159//cccc 0001 0r00 ++++ dddd ---- 0000 ----160//c = condition161//r = SPSR (0 = CPSR)162//d = rd163void ArmDSP::op_move_to_register_from_status_register() {164uint1 source = instruction >> 22;165uint4 d = instruction >> 12;166167r[d] = source ? spsr : cpsr;168}169170//msr{condition} (c,s)psr:{fields},rm171//cccc 0001 0r10 ffff ++++ ---- 0000 mmmm172//c = condition173//r = SPSR (0 = CPSR)174//f = field mask175//m = rm176void ArmDSP::op_move_to_status_register_from_register() {177uint1 source = instruction >> 22;178uint4 field = instruction >> 16;179uint4 m = instruction;180181PSR &psr = source ? spsr : cpsr;182if(field & 1) psr.setc(r[m]);183if(field & 2) psr.setx(r[m]);184if(field & 4) psr.sets(r[m]);185if(field & 8) psr.setf(r[m]);186}187188//{opcode}{condition}{s} rd,rm {shift} #immediate189//{opcode}{condition} rn,rm {shift} #immediate190//{opcode}{condition}{s} rd,rn,rm {shift} #immediate191//cccc 000o ooos nnnn dddd llll lss0 mmmm192//c = condition193//o = opcode194//s = save flags195//n = rn196//d = rd197//l = shift immmediate198//s = shift199//m = rm200void ArmDSP::op_data_immediate_shift() {201uint1 save = instruction >> 20;202uint5 shift = instruction >> 7;203uint2 mode = instruction >> 5;204uint4 m = instruction;205206uint32 rs = shift;207uint32 rm = r[m];208bool c = cpsr.c;209210if(mode == 0) lsl(c, rm, rs);211if(mode == 1) lsr(c, rm, rs ? rs : 32);212if(mode == 2) asr(c, rm, rs ? rs : 32);213if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm);214215shiftercarry = c;216opcode(rm);217}218219//{opcode}{condition}{s} rd,rm {shift} rs220//{opcode}{condition} rn,rm {shift} rs221//{opcode}{condition}{s} rd,rn,rm {shift} rs222//cccc 000o ooos nnnn dddd ssss 0ss1 mmmm223//c = condition224//o = opcode225//s = save flags226//n = rn227//d = rd228//s = rs229//s = shift230//m = rm231void ArmDSP::op_data_register_shift() {232uint1 save = instruction >> 20;233uint4 s = instruction >> 8;234uint2 mode = instruction >> 5;235uint4 m = instruction >> 0;236237uint8 rs = r[s];238uint32 rm = r[m];239bool c = cpsr.c;240241if(mode == 0) lsl(c, rm, rs < 33 ? rs : 33);242if(mode == 1) lsr(c, rm, rs < 33 ? rs : 33);243if(mode == 2) asr(c, rm, rs < 32 ? rs : 32);244if(mode == 3 && rs) ror(c, rm, rs & 31 == 0 ? 32 : rs & 31);245246shiftercarry = c;247opcode(rm);248}249250//{opcode}{condition}{s} rd,#immediate251//{opcode}{condition} rn,#immediate252//{opcode}{condition}{s} rd,rn,#immediate253//cccc 001o ooos nnnn dddd llll iiii iiii254//c = condition255//o = opcode256//s = save flags257//n = rn258//d = rd259//l = shift immediate260//i = immediate261void ArmDSP::op_data_immediate() {262uint1 save = instruction >> 20;263uint4 shift = instruction >> 8;264uint8 immediate = instruction;265266uint32 rs = shift << 1;267uint32 rm = (immediate >> rs) | (immediate << (32 - rs));268if(rs) shiftercarry = immediate >> 31;269270opcode(rm);271}272273//(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!}274//(ldr,str){condition}{b} rd,[rn]{,+/-offset}275//cccc 010p ubwl nnnn dddd iiii iiii iiii276//c = condition277//p = pre (0 = post-indexed addressing)278//u = up (add/sub offset to base)279//b = byte (1 = 32-bit)280//w = writeback281//l = load (0 = save)282//n = rn283//d = rd284//i = immediate285void ArmDSP::op_move_immediate_offset() {286uint1 p = instruction >> 24;287uint1 u = instruction >> 23;288uint1 b = instruction >> 22;289uint1 w = instruction >> 21;290uint1 l = instruction >> 20;291uint4 n = instruction >> 16;292uint4 d = instruction >> 12;293uint12 rm = instruction;294295uint32 rn = r[n];296auto &rd = r[d];297298if(p == 1) rn = u ? rn + rm : rn - rm;299if(l) rd = b ? bus_readbyte(rn) : bus_readword(rn);300else b ? bus_writebyte(rn, rd) : bus_writeword(rn, rd);301if(p == 0) rn = u ? rn + rm : rn - rm;302303if(p == 0 || w == 1) r[n] = rn;304}305306//(ldr)(str){condition}{b} rd,[rn,rm {mode} #immediate]{!}307//(ldr)(str){condition}{b} rd,[rn],rm {mode} #immediate308//cccc 011p ubwl nnnn dddd llll lss0 mmmm309//c = condition310//p = pre (0 = post-indexed addressing)311//u = up312//b = byte (1 = 32-bit)313//w = writeback314//l = load (0 = save)315//n = rn316//d = rd317//l = shift immediate318//s = shift mode319//m = rm320void ArmDSP::op_move_register_offset() {321uint1 p = instruction >> 24;322uint1 u = instruction >> 23;323uint1 b = instruction >> 22;324uint1 w = instruction >> 21;325uint1 l = instruction >> 20;326uint4 n = instruction >> 16;327uint4 d = instruction >> 12;328uint5 immediate = instruction >> 7;329uint2 mode = instruction >> 5;330uint4 m = instruction;331332uint32 rn = r[n];333auto &rd = r[d];334uint32 rs = immediate;335uint32 rm = r[m];336bool c = cpsr.c;337338if(mode == 0) lsl(c, rm, rs);339if(mode == 1) lsr(c, rm, rs ? rs : 32);340if(mode == 2) asr(c, rm, rs ? rs : 32);341if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm);342343if(p == 1) rn = u ? rn + rm : rn - rm;344if(l) rd = b ? bus_readbyte(rn) : bus_readword(rn);345else b ? bus_writebyte(rn, rd) : bus_writeword(rn, rd);346if(p == 0) rn = u ? rn + rm : rn - rm;347348if(p == 0 || w == 1) r[n] = rn;349}350351//(ldm,stm){condition}{mode} rn{!},{r...}352//cccc 100p uswl nnnn llll llll llll llll353//c = condition354//p = pre (0 = post-indexed addressing)355//u = up (add/sub offset to base)356//s = ???357//w = writeback358//l = load (0 = save)359//n = rn360//l = register list361void ArmDSP::op_move_multiple() {362uint1 p = instruction >> 24;363uint1 u = instruction >> 23;364uint1 s = instruction >> 22;365uint1 w = instruction >> 21;366uint1 l = instruction >> 20;367uint4 n = instruction >> 16;368uint16 list = instruction;369370uint32 rn = r[n];371if(p == 0 && u == 1) rn = rn + 0; //IA372if(p == 1 && u == 1) rn = rn + 4; //IB373if(p == 1 && u == 0) rn = rn - bit::count(list) * 4 + 0; //DB374if(p == 0 && u == 0) rn = rn - bit::count(list) * 4 + 4; //DA375376for(unsigned n = 0; n < 16; n++) {377if(list & (1 << n)) {378if(l) r[n] = bus_readword(rn);379else bus_writeword(rn, r[n]);380rn += 4;381}382}383384if(w) {385if(u == 1) r[n] = r[n] + bit::count(list) * 4; //IA, IB386if(u == 0) r[n] = r[n] - bit::count(list) * 4; //DA, DB387}388}389390//b{l}{condition} address391//cccc 101l dddd dddd dddd dddd dddd dddd392//c = condition393//l = link394//d = displacement (24-bit signed)395void ArmDSP::op_branch() {396uint1 l = instruction >> 24;397int24 displacement = instruction;398399if(l) r[14] = r[15] - 4;400r[15] += displacement * 4;401}402403#endif404405406