auto ARM::arm_opcode(uint32 rm) { uint4 opcode = instruction() >> 21; uint1 save = instruction() >> 20; uint4 n = instruction() >> 16; uint4 d = instruction() >> 12; uint32 rn = r(n); switch(opcode) { case 0: r(d) = bit(rn & rm); break; //AND case 1: r(d) = bit(rn ^ rm); break; //EOR case 2: r(d) = sub(rn, rm, 1); break; //SUB case 3: r(d) = sub(rm, rn, 1); break; //RSB case 4: r(d) = add(rn, rm, 0); break; //ADD case 5: r(d) = add(rn, rm, cpsr().c); break; //ADC case 6: r(d) = sub(rn, rm, cpsr().c); break; //SBC case 7: r(d) = sub(rm, rn, cpsr().c); break; //RSC case 8: bit(rn & rm); break; //TST case 9: bit(rn ^ rm); break; //TEQ case 10: sub(rn, rm, 1); break; //CMP case 11: add(rn, rm, 0); break; //CMN case 12: r(d) = bit(rn | rm); break; //ORR case 13: r(d) = bit(rm); break; //MOV case 14: r(d) = bit(rn & ~rm); break; //BIC case 15: r(d) = bit(~rm); break; //MVN } if(exceptionMode() && d == 15 && save) { cpsr() = spsr(); processor.setMode((Processor::Mode)cpsr().m); } } auto ARM::arm_move_to_status(uint32 rm) { uint1 source = instruction() >> 22; uint4 field = instruction() >> 16; if(source == 1) { if(mode() == Processor::Mode::USR) return; if(mode() == Processor::Mode::SYS) return; } PSR &psr = source ? spsr() : cpsr(); if(field & 1) { if(source == 1 || privilegedMode()) { psr.i = rm & 0x00000080; psr.f = rm & 0x00000040; psr.t = rm & 0x00000020; psr.m = rm & 0x0000001f; if(source == 0) processor.setMode((Processor::Mode)psr.m); } } if(field & 8) { psr.n = rm & 0x80000000; psr.z = rm & 0x40000000; psr.c = rm & 0x20000000; psr.v = rm & 0x10000000; } } //mul{condition}{s} rd,rm,rs //mla{condition}{s} rd,rm,rs,rn //cccc 0000 00as dddd nnnn ssss 1001 mmmm //c = condition //a = accumulate //s = save flags //d = rd //n = rn //s = rs //m = rm auto ARM::arm_op_multiply() { uint1 accumulate = instruction() >> 21; uint1 save = instruction() >> 20; uint4 d = instruction() >> 16; uint4 n = instruction() >> 12; uint4 s = instruction() >> 8; uint4 m = instruction(); r(d) = mul(accumulate ? r(n) : 0u, r(m), r(s)); } //(u,s)mull{condition}{s} rdlo,rdhi,rm,rs //(u,s)mlal{condition}{s} rdlo,rdhi,rm,rs //cccc 0000 1sas hhhh llll ssss 1001 mmmm //c = condition //s = sign-extend //a = accumulate //s = save flags //h = rdhi //l = rdlo //s = rs //m = rm auto ARM::arm_op_multiply_long() { uint1 signextend = instruction() >> 22; uint1 accumulate = instruction() >> 21; uint1 save = instruction() >> 20; uint4 dhi = instruction() >> 16; uint4 dlo = instruction() >> 12; uint4 s = instruction() >> 8; uint4 m = instruction(); uint64 rm = r(m); uint64 rs = r(s); if(signextend) { rm = (int32)rm; rs = (int32)rs; } uint64 rd = rm * rs; if(accumulate) rd += ((uint64)r(dhi) << 32) + ((uint64)r(dlo) << 0); r(dhi) = rd >> 32; r(dlo) = rd >> 0; if(save) { cpsr().n = r(dhi) >> 31; cpsr().z = r(dhi) == 0 && r(dlo) == 0; //cpsr().c = 0; //(undefined) //cpsr().v = 0; //(undefined) } } //swp{condition}{b} rd,rm,[rn] //cccc 0001 0b00 nnnn dddd ---- 1001 mmmm //c = condition //b = byte (0 = word) //n = rn //d = rd //m = rm auto ARM::arm_op_memory_swap() { uint1 byte = instruction() >> 22; uint4 n = instruction() >> 16; uint4 d = instruction() >> 12; uint4 m = instruction(); uint32 word = load((byte ? Byte : Word) | Nonsequential, r(n)); store((byte ? Byte : Word) | Nonsequential, r(n), r(m)); r(d) = word; } //(ldr,str){condition}h rd,[rn,rm]{!} //(ldr,str){condition}h rd,[rn],rm //cccc 000p u0wl nnnn dddd ---- 1011 mmmm //c = condition //p = pre (0 = post) //u = up //w = writeback //l = load (0 = save) //n = rn //d = rd //m = rm auto ARM::arm_op_move_half_register() { uint1 pre = instruction() >> 24; uint1 up = instruction() >> 23; uint1 writeback = instruction() >> 21; uint1 l = instruction() >> 20; uint4 n = instruction() >> 16; uint4 d = instruction() >> 12; uint4 m = instruction(); uint32 rn = r(n); uint32 rm = r(m); uint32 rd = r(d); if(pre == 1) rn = up ? rn + rm : rn - rm; if(l == 1) rd = load(Half | Nonsequential, rn); if(l == 0) store(Half | Nonsequential, rn, rd); if(pre == 0) rn = up ? rn + rm : rn - rm; if(pre == 0 || writeback == 1) r(n) = rn; if(l == 1) r(d) = rd; } //(ldr,str){condition}h rd,[rn{,+/-offset}]{!} //(ldr,str){condition}h rd,[rn]{,+/-offset} //cccc 000p u1wl nnnn dddd iiii 1011 iiii //c = condition //p = pre (0 = post) //u = up //w = writeback //l = load (0 = save) //n = rn //d = rd //i = immediate hi //i = immediate lo auto ARM::arm_op_move_half_immediate() { uint1 pre = instruction() >> 24; uint1 up = instruction() >> 23; uint1 writeback = instruction() >> 21; uint1 l = instruction() >> 20; uint4 n = instruction() >> 16; uint4 d = instruction() >> 12; uint4 ih = instruction() >> 8; uint4 il = instruction(); uint32 rn = r(n); uint32 rd = r(d); uint8 immediate = (ih << 4) + (il << 0); if(pre == 1) rn = up ? rn + immediate : rn - immediate; if(l == 1) rd = load(Half | Nonsequential, rn); if(l == 0) store(Half | Nonsequential, rn, rd); if(pre == 0) rn = up ? rn + immediate : rn - immediate; if(pre == 0 || writeback == 1) r(n) = rn; if(l == 1) r(d) = rd; } //ldr{condition}s(h,b) rd,[rn,rm]{!} //ldr{condition}s(h,b) rd,[rn],rm //cccc 000p u0w1 nnnn dddd ---- 11h1 mmmm //c = condition //p = pre (0 = post) //u = up //w = writeback //n = rn //d = rd //h = half (0 = byte) //m = rm auto ARM::arm_op_load_register() { uint1 pre = instruction() >> 24; uint1 up = instruction() >> 23; uint1 writeback = instruction() >> 21; uint4 n = instruction() >> 16; uint4 d = instruction() >> 12; uint1 half = instruction() >> 5; uint4 m = instruction(); uint32 rn = r(n); uint32 rm = r(m); uint32 rd = r(d); if(pre == 1) rn = up ? rn + rm : rn - rm; rd = load((half ? Half : Byte) | Nonsequential | Signed, rn); if(pre == 0) rn = up ? rn + rm : rn - rm; if(pre == 0 || writeback == 1) r(n) = rn; r(d) = rd; } //ldr{condition}s(h,b) rd,[rn{,+/-offset}]{!} //ldr{condition}s(h,b) rd,[rn]{,+/-offset} //cccc 000p u1w1 nnnn dddd iiii 11h1 iiii //c = condition //p = pre (0 = post) //u = up //w = writeback //n = rn //d = rd //i = immediate hi //h = half (0 = byte) //i = immediate lo auto ARM::arm_op_load_immediate() { uint1 pre = instruction() >> 24; uint1 up = instruction() >> 23; uint1 writeback = instruction() >> 21; uint4 n = instruction() >> 16; uint4 d = instruction() >> 12; uint4 ih = instruction() >> 8; uint1 half = instruction() >> 5; uint4 il = instruction(); uint32 rn = r(n); uint32 rd = r(d); uint8 immediate = (ih << 4) + (il << 0); if(pre == 1) rn = up ? rn + immediate : rn - immediate; rd = load((half ? Half : Byte) | Nonsequential | Signed, rn); if(pre == 0) rn = up ? rn + immediate : rn - immediate; if(pre == 0 || writeback == 1) r(n) = rn; r(d) = rd; } //mrs{condition} rd,(c,s)psr //cccc 0001 0r00 ++++ dddd ---- 0000 ---- //c = condition //r = SPSR (0 = CPSR) //d = rd auto ARM::arm_op_move_to_register_from_status() { uint1 source = instruction() >> 22; uint4 d = instruction() >> 12; if(source) { if(mode() == Processor::Mode::USR) return; if(mode() == Processor::Mode::SYS) return; } r(d) = source ? spsr() : cpsr(); } //msr{condition} (c,s)psr:{fields},rm //cccc 0001 0r10 ffff ++++ ---- 0000 mmmm //c = condition //r = SPSR (0 = CPSR) //f = field mask //m = rm auto ARM::arm_op_move_to_status_from_register() { uint4 m = instruction(); arm_move_to_status(r(m)); } //bx{condition} rm //cccc 0001 0010 ++++ ++++ ++++ 0001 mmmm //c = condition //m = rm auto ARM::arm_op_branch_exchange_register() { uint4 m = instruction(); cpsr().t = r(m) & 1; r(15) = r(m); } //msr{condition} (c,s)psr:{fields},#immediate //cccc 0011 0r10 ffff ++++ rrrr iiii iiii //c = condition //r = SPSR (0 = CPSR) //f = field mask //r = rotate //i = immediate auto ARM::arm_op_move_to_status_from_immediate() { uint4 rotate = instruction() >> 8; uint8 immediate = instruction(); uint32 rm = immediate; if(rotate) rm = ror(rm, 2 * rotate); arm_move_to_status(rm); } //{opcode}{condition}{s} rd,rm {shift} #immediate //{opcode}{condition} rn,rm {shift} #immediate //{opcode}{condition}{s} rd,rn,rm {shift} #immediate //cccc 000o ooos nnnn dddd llll lss0 mmmm //c = condition //o = opcode //s = save flags //n = rn //d = rd //l = shift immediate //s = shift //m = rm auto ARM::arm_op_data_immediate_shift() { uint1 save = instruction() >> 20; uint5 shift = instruction() >> 7; uint2 mode = instruction() >> 5; uint4 m = instruction(); uint32 rs = shift; uint32 rm = r(m); carryout() = cpsr().c; if(mode == 0) rm = lsl(rm, rs); if(mode == 1) rm = lsr(rm, rs ? rs : (uint32)32); if(mode == 2) rm = asr(rm, rs ? rs : (uint32)32); if(mode == 3) rm = rs ? ror(rm, rs) : rrx(rm); arm_opcode(rm); } //{opcode}{condition}{s} rd,rm {shift} rs //{opcode}{condition} rn,rm {shift} rs //{opcode}{condition}{s} rd,rn,rm {shift} rs //cccc 000o ooos nnnn dddd ssss 0ss1 mmmm //c = condition //o = opcode //s = save flags //n = rn //d = rd //s = rs //s = shift //m = rm auto ARM::arm_op_data_register_shift() { uint1 save = instruction() >> 20; uint4 s = instruction() >> 8; uint2 mode = instruction() >> 5; uint4 m = instruction(); uint8 rs = r(s) + (s == 15 ? 4 : 0); uint32 rm = r(m) + (m == 15 ? 4 : 0); carryout() = cpsr().c; if(mode == 0 ) rm = lsl(rm, rs < 33 ? rs : (uint8)33); if(mode == 1 ) rm = lsr(rm, rs < 33 ? rs : (uint8)33); if(mode == 2 ) rm = asr(rm, rs < 32 ? rs : (uint8)32); if(mode == 3 && rs) rm = ror(rm, rs & 31 == 0 ? 32 : rs & 31); arm_opcode(rm); } //{opcode}{condition}{s} rd,#immediate //{opcode}{condition} rn,#immediate //{opcode}{condition}{s} rd,rn,#immediate //cccc 001o ooos nnnn dddd ssss iiii iiii //c = condition //o = opcode //s = save flags //n = rn //d = rd //s = shift immediate //i = immediate auto ARM::arm_op_data_immediate() { uint1 save = instruction() >> 20; uint4 shift = instruction() >> 8; uint8 immediate = instruction(); uint32 rm = immediate; carryout() = cpsr().c; if(shift) rm = ror(immediate, 2 * shift); arm_opcode(rm); } //(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!} //(ldr,str){condition}{b} rd,[rn]{,+/-offset} //cccc 010p ubwl nnnn dddd iiii iiii iiii //c = condition //p = pre (0 = post-indexed addressing) //u = up (add/sub offset to base) //b = byte (1 = word) //w = writeback //l = load (0 = save) //n = rn //d = rd //i = immediate auto ARM::arm_op_move_immediate_offset() { uint1 pre = instruction() >> 24; uint1 up = instruction() >> 23; uint1 byte = instruction() >> 22; uint1 writeback = instruction() >> 21; uint1 l = instruction() >> 20; uint4 n = instruction() >> 16; uint4 d = instruction() >> 12; uint12 rm = instruction(); uint32 rn = r(n); uint32 rd = r(d); if(pre == 1) rn = up ? rn + rm : rn - rm; if(l == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn); if(l == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd); if(pre == 0) rn = up ? rn + rm : rn - rm; if(pre == 0 || writeback == 1) r(n) = rn; if(l == 1) r(d) = rd; } //(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{!} //(ldr,str){condition}{b} rd,[rn],rm {mode} #immediate //cccc 011p ubwl nnnn dddd llll lss0 mmmm //c = condition //p = pre (0 = post-indexed addressing) //u = up //b = byte (1 = word) //w = writeback //l = load (0 = save) //n = rn //d = rd //l = shift immediate //s = shift mode //m = rm auto ARM::arm_op_move_register_offset() { uint1 pre = instruction() >> 24; uint1 up = instruction() >> 23; uint1 byte = instruction() >> 22; uint1 writeback = instruction() >> 21; uint1 l = instruction() >> 20; uint4 n = instruction() >> 16; uint4 d = instruction() >> 12; uint5 immediate = instruction() >> 7; uint2 mode = instruction() >> 5; uint4 m = instruction(); uint32 rn = r(n); uint32 rd = r(d); uint32 rs = immediate; uint32 rm = r(m); bool c = cpsr().c; if(mode == 0) rm = lsl(rm, rs); if(mode == 1) rm = lsr(rm, rs ? rs : (uint32)32); if(mode == 2) rm = asr(rm, rs ? rs : (uint32)32); if(mode == 3) rm = rs ? ror(rm, rs) : rrx(rm); if(pre == 1) rn = up ? rn + rm : rn - rm; if(l == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn); if(l == 0) store((byte ? Byte : Word) | Nonsequential, rn, rd); if(pre == 0) rn = up ? rn + rm : rn - rm; if(pre == 0 || writeback == 1) r(n) = rn; if(l == 1) r(d) = rd; } //(ldm,stm){condition}{mode} rn{!},{r...} //cccc 100p uswl nnnn llll llll llll llll //c = condition //p = pre (0 = post-indexed addressing) //u = up (add/sub offset to base) //s = spsr copy -or- usr register copy //w = writeback //l = load (0 = save) //n = rn //l = register list auto ARM::arm_op_move_multiple() { uint1 pre = instruction() >> 24; uint1 up = instruction() >> 23; uint1 s = instruction() >> 22; uint1 writeback = instruction() >> 21; uint1 l = instruction() >> 20; uint4 n = instruction() >> 16; uint16 list = instruction(); uint32 rn = r(n); if(pre == 0 && up == 1) rn = rn + 0; //IA if(pre == 1 && up == 1) rn = rn + 4; //IB if(pre == 1 && up == 0) rn = rn - bit::count(list) * 4 + 0; //DB if(pre == 0 && up == 0) rn = rn - bit::count(list) * 4 + 4; //DA if(writeback && l == 1) { if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA, IB if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA, DB } Processor::Mode pmode = mode(); bool usr = false; if(s && l == 1 && (list & 0x8000) == 0) usr = true; if(s && l == 0) usr = true; if(usr) processor.setMode(Processor::Mode::USR); unsigned sequential = Nonsequential; for(unsigned m = 0; m < 16; m++) { if(list & 1 << m) { if(l == 1) r(m) = read(Word | sequential, rn); if(l == 0) write(Word | sequential, rn, r(m)); rn += 4; sequential = Sequential; } } if(usr) processor.setMode(pmode); if(l == 1) { idle(); if(s && (list & 0x8000)) { if(mode() != Processor::Mode::USR && mode() != Processor::Mode::SYS) { cpsr() = spsr(); processor.setMode((Processor::Mode)cpsr().m); } } } else { pipeline.nonsequential = true; } if(writeback && l == 0) { if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA, IB if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA, DB } } //b{l}{condition} address //cccc 101l dddd dddd dddd dddd dddd dddd //c = condition //l = link //d = displacement (24-bit signed) auto ARM::arm_op_branch() { uint1 link = instruction() >> 24; int24 displacement = instruction(); if(link) r(14) = r(15) - 4; r(15) += displacement * 4; } //swi #immediate //cccc 1111 iiii iiii iiii iiii iiii iiii //c = condition //i = immediate auto ARM::arm_op_software_interrupt() { uint24 immediate = instruction(); vector(0x00000008, Processor::Mode::SVC); }