mirror of https://github.com/stella-emu/stella.git
optimized thumb branch instructions
This commit is contained in:
parent
bb1b0ab953
commit
96d5a3ff5b
|
@ -135,12 +135,13 @@ Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt32 rom_size
|
||||||
cStart{c_start},
|
cStart{c_start},
|
||||||
cStack{c_stack},
|
cStack{c_stack},
|
||||||
decodedRom{make_unique<Op[]>(romSize / 2)}, // NOLINT
|
decodedRom{make_unique<Op[]>(romSize / 2)}, // NOLINT
|
||||||
|
decodedParam{make_unique<uInt32[]>(romSize / 2)}, // NOLINT
|
||||||
ram{ram_ptr},
|
ram{ram_ptr},
|
||||||
configuration{configurefor},
|
configuration{configurefor},
|
||||||
myCartridge{cartridge}
|
myCartridge{cartridge}
|
||||||
{
|
{
|
||||||
for(uInt32 i = 0; i < romSize / 2; ++i)
|
for(uInt32 i = 0; i < romSize / 2; ++i)
|
||||||
decodedRom[i] = decodeInstructionWord(CONV_RAMROM(rom[i]));
|
decodedRom[i] = decodeInstructionWord(CONV_RAMROM(rom[i]), i * 2);
|
||||||
|
|
||||||
setConsoleTiming(ConsoleTiming::ntsc);
|
setConsoleTiming(ConsoleTiming::ntsc);
|
||||||
#ifndef UNSAFE_OPTIMIZATIONS
|
#ifndef UNSAFE_OPTIMIZATIONS
|
||||||
|
@ -867,7 +868,7 @@ void Thumbulator::do_vflag_bit(uInt32 x)
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst) {
|
Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst, uInt32 pc) {
|
||||||
//ADC add with carry
|
//ADC add with carry
|
||||||
if((inst & 0xFFC0) == 0x4140) return Op::adc;
|
if((inst & 0xFFC0) == 0x4140) return Op::adc;
|
||||||
|
|
||||||
|
@ -901,11 +902,82 @@ Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst) {
|
||||||
//ASR(2) two register
|
//ASR(2) two register
|
||||||
if((inst & 0xFFC0) == 0x4100) return Op::asr2;
|
if((inst & 0xFFC0) == 0x4100) return Op::asr2;
|
||||||
|
|
||||||
//B(1) conditional branch
|
//B(1) conditional branch, decoded into its variants
|
||||||
if((inst & 0xF000) == 0xD000) return Op::b1;
|
if((inst & 0xF000) == 0xD000)
|
||||||
|
{
|
||||||
|
const uInt32 op = (inst >> 8) & 0xF;
|
||||||
|
uInt32 rb = inst & 0xFF;
|
||||||
|
|
||||||
|
if(rb & 0x80)
|
||||||
|
rb |= (~0U) << 8;
|
||||||
|
rb <<= 1;
|
||||||
|
rb += pc;
|
||||||
|
rb += 2;
|
||||||
|
decodedParam[pc / 2] = rb + 4;
|
||||||
|
|
||||||
|
switch(op)
|
||||||
|
{
|
||||||
|
case 0x0: //b eq z set
|
||||||
|
return Op::beq;
|
||||||
|
|
||||||
|
case 0x1: //b ne z clear
|
||||||
|
return Op::bne;
|
||||||
|
|
||||||
|
case 0x2: //b cs c set
|
||||||
|
return Op::bcs;
|
||||||
|
|
||||||
|
case 0x3: //b cc c clear
|
||||||
|
return Op::bcc;
|
||||||
|
|
||||||
|
case 0x4: //b mi n set
|
||||||
|
return Op::bmi;
|
||||||
|
|
||||||
|
case 0x5: //b pl n clear
|
||||||
|
return Op::bpl;
|
||||||
|
|
||||||
|
case 0x6: //b vs v set
|
||||||
|
return Op::bvs;
|
||||||
|
|
||||||
|
case 0x7: //b vc v clear
|
||||||
|
return Op::bvc;
|
||||||
|
|
||||||
|
case 0x8: //b hi c set z clear
|
||||||
|
return Op::bhi;
|
||||||
|
|
||||||
|
case 0x9: //b ls c clear or z set
|
||||||
|
return Op::bls;
|
||||||
|
|
||||||
|
case 0xA: //b ge N == V
|
||||||
|
return Op::bge;
|
||||||
|
|
||||||
|
case 0xB: //b lt N != V
|
||||||
|
return Op::blt;
|
||||||
|
|
||||||
|
case 0xC: //b gt Z==0 and N == V
|
||||||
|
return Op::bgt;
|
||||||
|
|
||||||
|
case 0xD: //b le Z==1 or N != V
|
||||||
|
return Op::ble;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Op::invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//B(2) unconditional branch
|
//B(2) unconditional branch
|
||||||
if((inst & 0xF800) == 0xE000) return Op::b2;
|
if((inst & 0xF800) == 0xE000)
|
||||||
|
{
|
||||||
|
uInt32 rb = (inst >> 0) & 0x7FF;
|
||||||
|
|
||||||
|
if(rb & (1 << 10))
|
||||||
|
rb |= (~0U) << 11;
|
||||||
|
rb <<= 1;
|
||||||
|
rb += pc;
|
||||||
|
rb += 2;
|
||||||
|
decodedParam[pc / 2] = rb + 4;
|
||||||
|
|
||||||
|
return Op::b2;
|
||||||
|
}
|
||||||
|
|
||||||
//BIC
|
//BIC
|
||||||
if((inst & 0xFFC0) == 0x4380) return Op::bic;
|
if((inst & 0xFFC0) == 0x4380) return Op::bic;
|
||||||
|
@ -913,8 +985,14 @@ Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst) {
|
||||||
//BKPT
|
//BKPT
|
||||||
if((inst & 0xFF00) == 0xBE00) return Op::bkpt;
|
if((inst & 0xFF00) == 0xBE00) return Op::bkpt;
|
||||||
|
|
||||||
//BL/BLX(1)
|
//BL/BLX(1) decoded into its variants
|
||||||
if((inst & 0xE000) == 0xE000) return Op::blx1;
|
if((inst & 0xE000) == 0xE000)
|
||||||
|
{
|
||||||
|
if((inst & 0x1800) == 0x1000) return Op::bl;
|
||||||
|
else if((inst & 0x1800) == 0x1800) return Op::blx_thumb;
|
||||||
|
else if((inst & 0x1800) == 0x0800) return Op::blx_arm;
|
||||||
|
return Op::invalid;
|
||||||
|
}
|
||||||
|
|
||||||
//BLX(2)
|
//BLX(2)
|
||||||
if((inst & 0xFF87) == 0x4780) return Op::blx2;
|
if((inst & 0xFF87) == 0x4780) return Op::blx2;
|
||||||
|
@ -1091,9 +1169,9 @@ Thumbulator::Op Thumbulator::decodeInstructionWord(uint16_t inst) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
int Thumbulator::execute() // NOLINT (readability-function-size)
|
inline int Thumbulator::execute() // NOLINT (readability-function-size)
|
||||||
{
|
{
|
||||||
uInt32 sp, inst, ra, rb, rc, rm, rd, rn, rs, op; // NOLINT
|
uInt32 sp, inst, ra, rb, rc, rm, rd, rn, rs; // NOLINT
|
||||||
|
|
||||||
uInt32 pc = read_register(15);
|
uInt32 pc = read_register(15);
|
||||||
|
|
||||||
|
@ -1113,7 +1191,7 @@ int Thumbulator::execute() // NOLINT (readability-function-size)
|
||||||
if ((instructionPtr & 0xF0000000) == 0 && instructionPtr < romSize)
|
if ((instructionPtr & 0xF0000000) == 0 && instructionPtr < romSize)
|
||||||
decodedOp = decodedRom[instructionPtr >> 1];
|
decodedOp = decodedRom[instructionPtr >> 1];
|
||||||
else
|
else
|
||||||
decodedOp = decodeInstructionWord(inst);
|
decodedOp = decodeInstructionWord(inst, pc);
|
||||||
#else
|
#else
|
||||||
decodedOp = decodedRom[(instructionPtr & ROMADDMASK) >> 1];
|
decodedOp = decodedRom[(instructionPtr & ROMADDMASK) >> 1];
|
||||||
#endif
|
#endif
|
||||||
|
@ -1350,125 +1428,168 @@ int Thumbulator::execute() // NOLINT (readability-function-size)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//B(1) conditional branch
|
//B(1) conditional branch variants:
|
||||||
case Op::b1: {
|
// (beq, bne, bcs, bcc, bmi, bpl, bvs, bvc, bhi, bls, bge, blt, bgt, ble)
|
||||||
#ifdef THUMB_STATS
|
case Op::beq: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
++_stats.branches;
|
++_stats.branches;
|
||||||
#endif
|
#endif
|
||||||
rb = inst & 0xFF;
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
if(rb & 0x80)
|
DO_DISS(statusMsg << "beq 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
rb |= (~0U) << 8;
|
if(cpsr & CPSR_Z)
|
||||||
rb <<= 1;
|
write_register(15, rb);
|
||||||
rb += pc;
|
return 0;
|
||||||
rb += 2;
|
}
|
||||||
|
|
||||||
op = (inst >> 8) & 0xF;
|
case Op::bne: {
|
||||||
switch(op)
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "bne 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if(!(cpsr & CPSR_Z))
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::bcs: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "bcs 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if(cpsr & CPSR_C)
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::bcc: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "bcc 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if(!(cpsr & CPSR_C))
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::bmi: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "bmi 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if(cpsr & CPSR_N)
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::bpl: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "bpl 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if(!(cpsr & CPSR_N))
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::bvs: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "bvs 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if(cpsr & CPSR_V)
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::bvc: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "bvc 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if(!(cpsr & CPSR_V))
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::bhi: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "bhi 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if((cpsr & CPSR_C) && (!(cpsr & CPSR_Z)))
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::bls: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "bls 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if((cpsr & CPSR_Z) || (!(cpsr & CPSR_C)))
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::bge: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "bge 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if(((cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
|
||||||
|
((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))))
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::blt: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "blt 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if((!(cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
|
||||||
|
(((cpsr & CPSR_N)) && !(cpsr & CPSR_V)))
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::bgt: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "bgt 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if(!(cpsr & CPSR_Z))
|
||||||
{
|
{
|
||||||
case 0x0: //b eq z set
|
if(((cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
|
||||||
DO_DISS(statusMsg << "beq 0x" << Base::HEX8 << (rb-3) << endl);
|
((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))))
|
||||||
if(cpsr & CPSR_Z)
|
write_register(15, rb);
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0x1: //b ne z clear
|
|
||||||
DO_DISS(statusMsg << "bne 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if(!(cpsr & CPSR_Z))
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0x2: //b cs c set
|
|
||||||
DO_DISS(statusMsg << "bcs 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if(cpsr & CPSR_C)
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0x3: //b cc c clear
|
|
||||||
DO_DISS(statusMsg << "bcc 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if(!(cpsr & CPSR_C))
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0x4: //b mi n set
|
|
||||||
DO_DISS(statusMsg << "bmi 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if(cpsr & CPSR_N)
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0x5: //b pl n clear
|
|
||||||
DO_DISS(statusMsg << "bpl 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if(!(cpsr & CPSR_N))
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0x6: //b vs v set
|
|
||||||
DO_DISS(statusMsg << "bvs 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if(cpsr & CPSR_V)
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0x7: //b vc v clear
|
|
||||||
DO_DISS(statusMsg << "bvc 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if(!(cpsr & CPSR_V))
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0x8: //b hi c set z clear
|
|
||||||
DO_DISS(statusMsg << "bhi 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if((cpsr & CPSR_C) && (!(cpsr & CPSR_Z)))
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0x9: //b ls c clear or z set
|
|
||||||
DO_DISS(statusMsg << "bls 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if((cpsr & CPSR_Z) || (!(cpsr & CPSR_C)))
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0xA: //b ge N == V
|
|
||||||
DO_DISS(statusMsg << "bge 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if(((cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
|
|
||||||
((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))))
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0xB: //b lt N != V
|
|
||||||
DO_DISS(statusMsg << "blt 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if((!(cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
|
|
||||||
(((cpsr & CPSR_N)) && !(cpsr & CPSR_V)))
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0xC: //b gt Z==0 and N == V
|
|
||||||
DO_DISS(statusMsg << "bgt 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if(!(cpsr & CPSR_Z))
|
|
||||||
{
|
|
||||||
if(((cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
|
|
||||||
((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))))
|
|
||||||
write_register(15, rb);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0xD: //b le Z==1 or N != V
|
|
||||||
DO_DISS(statusMsg << "ble 0x" << Base::HEX8 << (rb-3) << endl);
|
|
||||||
if((cpsr & CPSR_Z) ||
|
|
||||||
(!(cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
|
|
||||||
(((cpsr & CPSR_N)) && !(cpsr & CPSR_V)))
|
|
||||||
write_register(15, rb);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case 0xE:
|
|
||||||
//undefined instruction
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 0xF:
|
|
||||||
//swi
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
break;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op::ble: {
|
||||||
|
#ifdef THUMB_STATS
|
||||||
|
++_stats.branches;
|
||||||
|
#endif
|
||||||
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
|
DO_DISS(statusMsg << "ble 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
|
if((cpsr & CPSR_Z) ||
|
||||||
|
(!(cpsr & CPSR_N) && (cpsr & CPSR_V)) ||
|
||||||
|
(((cpsr & CPSR_N)) && !(cpsr & CPSR_V)))
|
||||||
|
write_register(15, rb);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//B(2) unconditional branch
|
//B(2) unconditional branch
|
||||||
|
@ -1476,12 +1597,7 @@ int Thumbulator::execute() // NOLINT (readability-function-size)
|
||||||
#ifdef THUMB_STATS
|
#ifdef THUMB_STATS
|
||||||
++_stats.branches;
|
++_stats.branches;
|
||||||
#endif
|
#endif
|
||||||
rb = (inst >> 0) & 0x7FF;
|
rb = decodedParam[instructionPtr >> 1];
|
||||||
if(rb & (1 << 10))
|
|
||||||
rb |= (~0U) << 11;
|
|
||||||
rb <<= 1;
|
|
||||||
rb += pc;
|
|
||||||
rb += 2;
|
|
||||||
DO_DISS(statusMsg << "B 0x" << Base::HEX8 << (rb-3) << endl);
|
DO_DISS(statusMsg << "B 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
write_register(15, rb);
|
write_register(15, rb);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1510,44 +1626,43 @@ int Thumbulator::execute() // NOLINT (readability-function-size)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//BL/BLX(1)
|
//BL/BLX(1) variants
|
||||||
case Op::blx1: {
|
// (bl, blx_thumb, blx_arm)
|
||||||
if((inst & 0x1800) == 0x1000) //H=b10
|
case Op::bl: {
|
||||||
{
|
// branch to label
|
||||||
DO_DISS(statusMsg << endl);
|
DO_DISS(statusMsg << endl);
|
||||||
rb = inst & ((1 << 11) - 1);
|
rb = inst & ((1 << 11) - 1);
|
||||||
if(rb & 1<<10) rb |= (~((1 << 11) - 1)); //sign extend
|
if(rb & 1 << 10) rb |= (~((1 << 11) - 1)); //sign extend
|
||||||
rb <<= 12;
|
rb <<= 12;
|
||||||
rb += pc;
|
rb += pc;
|
||||||
write_register(14, rb);
|
write_register(14, rb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if((inst & 0x1800) == 0x1800) //H=b11
|
|
||||||
{
|
case Op::blx_thumb: {
|
||||||
//branch to thumb
|
// branch to label, switch to thumb
|
||||||
rb = read_register(14);
|
rb = read_register(14);
|
||||||
rb += (inst & ((1 << 11) - 1)) << 1;
|
rb += (inst & ((1 << 11) - 1)) << 1;
|
||||||
rb += 2;
|
rb += 2;
|
||||||
DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl);
|
DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
write_register(14, (pc-2) | 1);
|
write_register(14, (pc-2) | 1);
|
||||||
write_register(15, rb);
|
write_register(15, rb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if((inst & 0x1800) == 0x0800) //H=b01
|
|
||||||
{
|
case Op::blx_arm: {
|
||||||
//fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst);
|
// branch to label, switch to arm
|
||||||
// fxq: this should exit the code without having to detect it
|
//fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst);
|
||||||
// TJ: seems to be not used
|
// fxq: this should exit the code without having to detect it
|
||||||
rb = read_register(14);
|
// TJ: seems to be not used
|
||||||
rb += (inst & ((1 << 11) - 1)) << 1;
|
rb = read_register(14);
|
||||||
rb &= 0xFFFFFFFC;
|
rb += (inst & ((1 << 11) - 1)) << 1;
|
||||||
rb += 2;
|
rb &= 0xFFFFFFFC;
|
||||||
DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl);
|
rb += 2;
|
||||||
write_register(14, (pc-2) | 1);
|
DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl);
|
||||||
write_register(15, rb);
|
write_register(14, (pc-2) | 1);
|
||||||
return 0;
|
write_register(15, rb);
|
||||||
}
|
return 0;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//BLX(2)
|
//BLX(2)
|
||||||
|
|
|
@ -47,7 +47,7 @@ class Cartridge;
|
||||||
|
|
||||||
#ifdef DEBUGGER_SUPPORT
|
#ifdef DEBUGGER_SUPPORT
|
||||||
#define THUMB_CYCLE_COUNT
|
#define THUMB_CYCLE_COUNT
|
||||||
//#define COUNT_OPS
|
#define COUNT_OPS
|
||||||
#define THUMB_STATS
|
#define THUMB_STATS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -160,10 +160,14 @@ class Thumbulator
|
||||||
add1, add2, add3, add4, add5, add6, add7,
|
add1, add2, add3, add4, add5, add6, add7,
|
||||||
and_,
|
and_,
|
||||||
asr1, asr2,
|
asr1, asr2,
|
||||||
b1, b2,
|
// b1 variants:
|
||||||
|
beq, bne, bcs, bcc, bmi, bpl, bvs, bvc, bhi, bls, bge, blt, bgt, ble,
|
||||||
|
b2,
|
||||||
bic,
|
bic,
|
||||||
bkpt,
|
bkpt,
|
||||||
blx1, blx2,
|
// blx1 variants:
|
||||||
|
bl, blx_thumb, blx_arm,
|
||||||
|
blx2,
|
||||||
bx,
|
bx,
|
||||||
cmn,
|
cmn,
|
||||||
cmp1, cmp2, cmp3,
|
cmp1, cmp2, cmp3,
|
||||||
|
@ -236,7 +240,7 @@ class Thumbulator
|
||||||
void write32(uInt32 addr, uInt32 data);
|
void write32(uInt32 addr, uInt32 data);
|
||||||
void updateTimer(uInt32 cycles);
|
void updateTimer(uInt32 cycles);
|
||||||
|
|
||||||
static Op decodeInstructionWord(uint16_t inst);
|
Op decodeInstructionWord(uint16_t inst, uInt32 pc);
|
||||||
|
|
||||||
void do_zflag(uInt32 x);
|
void do_zflag(uInt32 x);
|
||||||
void do_nflag(uInt32 x);
|
void do_nflag(uInt32 x);
|
||||||
|
@ -274,6 +278,7 @@ class Thumbulator
|
||||||
uInt32 cStart{0};
|
uInt32 cStart{0};
|
||||||
uInt32 cStack{0};
|
uInt32 cStack{0};
|
||||||
const unique_ptr<Op[]> decodedRom; // NOLINT
|
const unique_ptr<Op[]> decodedRom; // NOLINT
|
||||||
|
const unique_ptr<uInt32[]> decodedParam; // NOLINT
|
||||||
uInt16* ram{nullptr};
|
uInt16* ram{nullptr};
|
||||||
std::array<uInt32, 16> reg_norm; // normal execution mode, do not have a thread mode
|
std::array<uInt32, 16> reg_norm; // normal execution mode, do not have a thread mode
|
||||||
uInt32 cpsr{0};
|
uInt32 cpsr{0};
|
||||||
|
|
Loading…
Reference in New Issue