mirror of https://github.com/stella-emu/stella.git
Hook up ARM emulation. Crashes and dies right now.
This commit is contained in:
parent
39eb36083b
commit
32b8bbd32e
|
@ -35,6 +35,8 @@ using namespace elfEnvironment;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr size_t TRANSACTION_QUEUE_CAPACITY = 16384;
|
constexpr size_t TRANSACTION_QUEUE_CAPACITY = 16384;
|
||||||
|
constexpr uInt32 ARM_RUNAHED_MIN = 3;
|
||||||
|
constexpr uInt32 ARM_RUNAHED_MAX = 6;
|
||||||
|
|
||||||
#ifdef DUMP_ELF
|
#ifdef DUMP_ELF
|
||||||
void dumpElf(const ElfFile& elf)
|
void dumpElf(const ElfFile& elf)
|
||||||
|
@ -201,6 +203,7 @@ void CartridgeELF::reset()
|
||||||
std::fill_n(myLastPeekResult.get(), 0x1000, 0);
|
std::fill_n(myLastPeekResult.get(), 0x1000, 0);
|
||||||
myIsBusDriven = false;
|
myIsBusDriven = false;
|
||||||
myDriveBusValue = 0;
|
myDriveBusValue = 0;
|
||||||
|
myArmCycles = 0;
|
||||||
|
|
||||||
std::memset(mySectionStack.get(), 0, STACK_SIZE);
|
std::memset(mySectionStack.get(), 0, STACK_SIZE);
|
||||||
std::memset(mySectionText.get(), 0, TEXT_SIZE);
|
std::memset(mySectionText.get(), 0, TEXT_SIZE);
|
||||||
|
@ -292,6 +295,8 @@ const ByteBuffer& CartridgeELF::getImage(size_t& size) const
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt8 CartridgeELF::overdrivePeek(uInt16 address, uInt8 value)
|
uInt8 CartridgeELF::overdrivePeek(uInt16 address, uInt8 value)
|
||||||
{
|
{
|
||||||
|
runArm();
|
||||||
|
|
||||||
value = driveBus(address, value);
|
value = driveBus(address, value);
|
||||||
|
|
||||||
if (address & 0x1000) {
|
if (address & 0x1000) {
|
||||||
|
@ -305,6 +310,8 @@ uInt8 CartridgeELF::overdrivePeek(uInt16 address, uInt8 value)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt8 CartridgeELF::overdrivePoke(uInt16 address, uInt8 value)
|
uInt8 CartridgeELF::overdrivePoke(uInt16 address, uInt8 value)
|
||||||
{
|
{
|
||||||
|
runArm();
|
||||||
|
|
||||||
return driveBus(address, value);
|
return driveBus(address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,4 +459,18 @@ void CartridgeELF::jumpToMain()
|
||||||
.setRegister(15, myArmEntrypoint);
|
.setRegister(15, myArmEntrypoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CartridgeELF::runArm()
|
||||||
|
{
|
||||||
|
if (myArmCycles >= (mySystem->cycles() + ARM_RUNAHED_MIN) * myArmCyclesPer6502Cycle) return;
|
||||||
|
|
||||||
|
const uInt32 cyclesGoal =
|
||||||
|
(mySystem->cycles() + ARM_RUNAHED_MAX) * myArmCyclesPer6502Cycle - myArmCycles;
|
||||||
|
uInt32 cycles;
|
||||||
|
|
||||||
|
const CortexM0::err_t err = myCortexEmu.run(cyclesGoal, cycles);
|
||||||
|
myArmCycles += cycles;
|
||||||
|
|
||||||
|
if (err != 0) FatalEmulationError::raise("error executing ARM code: " + CortexM0::describeError(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,8 @@ class CartridgeELF: public Cartridge {
|
||||||
uInt32 getSystemType() const;
|
uInt32 getSystemType() const;
|
||||||
void jumpToMain();
|
void jumpToMain();
|
||||||
|
|
||||||
|
void runArm();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ByteBuffer myImage;
|
ByteBuffer myImage;
|
||||||
size_t myImageSize{0};
|
size_t myImageSize{0};
|
||||||
|
@ -102,6 +104,8 @@ class CartridgeELF: public Cartridge {
|
||||||
|
|
||||||
ConsoleTiming myConsoleTiming{ConsoleTiming::ntsc};
|
ConsoleTiming myConsoleTiming{ConsoleTiming::ntsc};
|
||||||
uInt32 myArmCyclesPer6502Cycle{80};
|
uInt32 myArmCyclesPer6502Cycle{80};
|
||||||
|
|
||||||
|
uInt64 myArmCycles{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CARTRIDGE_ELF
|
#endif // CARTRIDGE_ELF
|
||||||
|
|
|
@ -84,333 +84,391 @@ namespace {
|
||||||
constexpr uInt32 PAGEMAP_SIZE = 0x100000000 / 4096;
|
constexpr uInt32 PAGEMAP_SIZE = 0x100000000 / 4096;
|
||||||
|
|
||||||
enum class Op : uInt8 {
|
enum class Op : uInt8 {
|
||||||
adc,
|
adc,
|
||||||
add1, add2, add3, add4, add5, add6, add7,
|
add1, add2, add3, add4, add5, add6, add7,
|
||||||
and_,
|
and_,
|
||||||
asr1, asr2,
|
asr1, asr2,
|
||||||
// b1 variants:
|
// b1 variants:
|
||||||
beq, bne, bcs, bcc, bmi, bpl, bvs, bvc, bhi, bls, bge, blt, bgt, ble,
|
beq, bne, bcs, bcc, bmi, bpl, bvs, bvc, bhi, bls, bge, blt, bgt, ble,
|
||||||
b2,
|
b2,
|
||||||
bic,
|
bic,
|
||||||
bkpt,
|
bkpt,
|
||||||
// blx1 variants:
|
// blx1 variants:
|
||||||
bl, blx_thumb,
|
bl, blx_thumb,
|
||||||
blx2,
|
blx2,
|
||||||
bx,
|
bx,
|
||||||
cmn,
|
cmn,
|
||||||
cmp1, cmp2, cmp3,
|
cmp1, cmp2, cmp3,
|
||||||
cpy,
|
cpy,
|
||||||
eor,
|
eor,
|
||||||
ldmia,
|
ldmia,
|
||||||
ldr1, ldr2, ldr3, ldr4,
|
ldr1, ldr2, ldr3, ldr4,
|
||||||
ldrb1, ldrb2,
|
ldrb1, ldrb2,
|
||||||
ldrh1, ldrh2,
|
ldrh1, ldrh2,
|
||||||
ldrsb,
|
ldrsb,
|
||||||
ldrsh,
|
ldrsh,
|
||||||
lsl1, lsl2,
|
lsl1, lsl2,
|
||||||
lsr1, lsr2,
|
lsr1, lsr2,
|
||||||
mov1, mov2, mov3,
|
mov1, mov2, mov3,
|
||||||
mul,
|
mul,
|
||||||
mvn,
|
mvn,
|
||||||
neg,
|
neg,
|
||||||
orr,
|
orr,
|
||||||
pop,
|
pop,
|
||||||
push,
|
push,
|
||||||
rev,
|
rev,
|
||||||
rev16,
|
rev16,
|
||||||
revsh,
|
revsh,
|
||||||
ror,
|
ror,
|
||||||
sbc,
|
sbc,
|
||||||
setend,
|
setend,
|
||||||
stmia,
|
stmia,
|
||||||
str1, str2, str3,
|
str1, str2, str3,
|
||||||
strb1, strb2,
|
strb1, strb2,
|
||||||
strh1, strh2,
|
strh1, strh2,
|
||||||
sub1, sub2, sub3, sub4,
|
sub1, sub2, sub3, sub4,
|
||||||
swi,
|
swi,
|
||||||
sxtb,
|
sxtb,
|
||||||
sxth,
|
sxth,
|
||||||
tst,
|
tst,
|
||||||
uxtb,
|
uxtb,
|
||||||
uxth,
|
uxth,
|
||||||
numOps,
|
numOps,
|
||||||
invalid,
|
invalid,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Op decodeInstructionWord(uInt16 inst)
|
inline Op decodeInstructionWord(uInt16 inst)
|
||||||
|
{
|
||||||
|
//ADC add with carry
|
||||||
|
if((inst & 0xFFC0) == 0x4140) return Op::adc;
|
||||||
|
|
||||||
|
//ADD(1) small immediate two registers
|
||||||
|
if((inst & 0xFE00) == 0x1C00 && (inst >> 6) & 0x7) return Op::add1;
|
||||||
|
|
||||||
|
//ADD(2) big immediate one register
|
||||||
|
if((inst & 0xF800) == 0x3000) return Op::add2;
|
||||||
|
|
||||||
|
//ADD(3) three registers
|
||||||
|
if((inst & 0xFE00) == 0x1800) return Op::add3;
|
||||||
|
|
||||||
|
//ADD(4) two registers one or both high no flags
|
||||||
|
if((inst & 0xFF00) == 0x4400) return Op::add4;
|
||||||
|
|
||||||
|
//ADD(5) rd = pc plus immediate
|
||||||
|
if((inst & 0xF800) == 0xA000) return Op::add5;
|
||||||
|
|
||||||
|
//ADD(6) rd = sp plus immediate
|
||||||
|
if((inst & 0xF800) == 0xA800) return Op::add6;
|
||||||
|
|
||||||
|
//ADD(7) sp plus immediate
|
||||||
|
if((inst & 0xFF80) == 0xB000) return Op::add7;
|
||||||
|
|
||||||
|
//AND
|
||||||
|
if((inst & 0xFFC0) == 0x4000) return Op::and_;
|
||||||
|
|
||||||
|
//ASR(1) two register immediate
|
||||||
|
if((inst & 0xF800) == 0x1000) return Op::asr1;
|
||||||
|
|
||||||
|
//ASR(2) two register
|
||||||
|
if((inst & 0xFFC0) == 0x4100) return Op::asr2;
|
||||||
|
|
||||||
|
//B(1) conditional branch, decoded into its variants
|
||||||
|
if((inst & 0xF000) == 0xD000)
|
||||||
{
|
{
|
||||||
//ADC add with carry
|
switch((inst >> 8) & 0xF)
|
||||||
if((inst & 0xFFC0) == 0x4140) return Op::adc;
|
|
||||||
|
|
||||||
//ADD(1) small immediate two registers
|
|
||||||
if((inst & 0xFE00) == 0x1C00 && (inst >> 6) & 0x7) return Op::add1;
|
|
||||||
|
|
||||||
//ADD(2) big immediate one register
|
|
||||||
if((inst & 0xF800) == 0x3000) return Op::add2;
|
|
||||||
|
|
||||||
//ADD(3) three registers
|
|
||||||
if((inst & 0xFE00) == 0x1800) return Op::add3;
|
|
||||||
|
|
||||||
//ADD(4) two registers one or both high no flags
|
|
||||||
if((inst & 0xFF00) == 0x4400) return Op::add4;
|
|
||||||
|
|
||||||
//ADD(5) rd = pc plus immediate
|
|
||||||
if((inst & 0xF800) == 0xA000) return Op::add5;
|
|
||||||
|
|
||||||
//ADD(6) rd = sp plus immediate
|
|
||||||
if((inst & 0xF800) == 0xA800) return Op::add6;
|
|
||||||
|
|
||||||
//ADD(7) sp plus immediate
|
|
||||||
if((inst & 0xFF80) == 0xB000) return Op::add7;
|
|
||||||
|
|
||||||
//AND
|
|
||||||
if((inst & 0xFFC0) == 0x4000) return Op::and_;
|
|
||||||
|
|
||||||
//ASR(1) two register immediate
|
|
||||||
if((inst & 0xF800) == 0x1000) return Op::asr1;
|
|
||||||
|
|
||||||
//ASR(2) two register
|
|
||||||
if((inst & 0xFFC0) == 0x4100) return Op::asr2;
|
|
||||||
|
|
||||||
//B(1) conditional branch, decoded into its variants
|
|
||||||
if((inst & 0xF000) == 0xD000)
|
|
||||||
{
|
{
|
||||||
switch((inst >> 8) & 0xF)
|
case 0x0: //b eq z set
|
||||||
{
|
return Op::beq;
|
||||||
case 0x0: //b eq z set
|
|
||||||
return Op::beq;
|
|
||||||
|
|
||||||
case 0x1: //b ne z clear
|
case 0x1: //b ne z clear
|
||||||
return Op::bne;
|
return Op::bne;
|
||||||
|
|
||||||
case 0x2: //b cs c set
|
case 0x2: //b cs c set
|
||||||
return Op::bcs;
|
return Op::bcs;
|
||||||
|
|
||||||
case 0x3: //b cc c clear
|
case 0x3: //b cc c clear
|
||||||
return Op::bcc;
|
return Op::bcc;
|
||||||
|
|
||||||
case 0x4: //b mi n set
|
case 0x4: //b mi n set
|
||||||
return Op::bmi;
|
return Op::bmi;
|
||||||
|
|
||||||
case 0x5: //b pl n clear
|
case 0x5: //b pl n clear
|
||||||
return Op::bpl;
|
return Op::bpl;
|
||||||
|
|
||||||
case 0x6: //b vs v set
|
case 0x6: //b vs v set
|
||||||
return Op::bvs;
|
return Op::bvs;
|
||||||
|
|
||||||
case 0x7: //b vc v clear
|
case 0x7: //b vc v clear
|
||||||
return Op::bvc;
|
return Op::bvc;
|
||||||
|
|
||||||
case 0x8: //b hi c set z clear
|
case 0x8: //b hi c set z clear
|
||||||
return Op::bhi;
|
return Op::bhi;
|
||||||
|
|
||||||
case 0x9: //b ls c clear or z set
|
case 0x9: //b ls c clear or z set
|
||||||
return Op::bls;
|
return Op::bls;
|
||||||
|
|
||||||
case 0xA: //b ge N == V
|
case 0xA: //b ge N == V
|
||||||
return Op::bge;
|
return Op::bge;
|
||||||
|
|
||||||
case 0xB: //b lt N != V
|
case 0xB: //b lt N != V
|
||||||
return Op::blt;
|
return Op::blt;
|
||||||
|
|
||||||
case 0xC: //b gt Z==0 and N == V
|
case 0xC: //b gt Z==0 and N == V
|
||||||
return Op::bgt;
|
return Op::bgt;
|
||||||
|
|
||||||
case 0xD: //b le Z==1 or N != V
|
case 0xD: //b le Z==1 or N != V
|
||||||
return Op::ble;
|
return Op::ble;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return Op::invalid;
|
return Op::invalid;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//B(2) unconditional branch
|
//B(2) unconditional branch
|
||||||
if((inst & 0xF800) == 0xE000) return Op::b2;
|
if((inst & 0xF800) == 0xE000) return Op::b2;
|
||||||
|
|
||||||
//BIC
|
//BIC
|
||||||
if((inst & 0xFFC0) == 0x4380) return Op::bic;
|
if((inst & 0xFFC0) == 0x4380) return Op::bic;
|
||||||
|
|
||||||
//BKPT
|
//BKPT
|
||||||
if((inst & 0xFF00) == 0xBE00) return Op::bkpt;
|
if((inst & 0xFF00) == 0xBE00) return Op::bkpt;
|
||||||
|
|
||||||
//BL/BLX(1) decoded into its variants
|
|
||||||
if((inst & 0xE000) == 0xE000)
|
|
||||||
{
|
|
||||||
if((inst & 0x1800) == 0x1000) return Op::bl;
|
|
||||||
else if((inst & 0x1800) == 0x1800) return Op::blx_thumb;
|
|
||||||
return Op::invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
//BLX(2)
|
|
||||||
if((inst & 0xFF87) == 0x4780) return Op::blx2;
|
|
||||||
|
|
||||||
//BX
|
|
||||||
if((inst & 0xFF87) == 0x4700) return Op::bx;
|
|
||||||
|
|
||||||
//CMN
|
|
||||||
if((inst & 0xFFC0) == 0x42C0) return Op::cmn;
|
|
||||||
|
|
||||||
//CMP(1) compare immediate
|
|
||||||
if((inst & 0xF800) == 0x2800) return Op::cmp1;
|
|
||||||
|
|
||||||
//CMP(2) compare register
|
|
||||||
if((inst & 0xFFC0) == 0x4280) return Op::cmp2;
|
|
||||||
|
|
||||||
//CMP(3) compare high register
|
|
||||||
if((inst & 0xFF00) == 0x4500) return Op::cmp3;
|
|
||||||
|
|
||||||
//CPY copy high register
|
|
||||||
if((inst & 0xFFC0) == 0x4600) return Op::cpy;
|
|
||||||
|
|
||||||
//EOR
|
|
||||||
if((inst & 0xFFC0) == 0x4040) return Op::eor;
|
|
||||||
|
|
||||||
//LDMIA
|
|
||||||
if((inst & 0xF800) == 0xC800) return Op::ldmia;
|
|
||||||
|
|
||||||
//LDR(1) two register immediate
|
|
||||||
if((inst & 0xF800) == 0x6800) return Op::ldr1;
|
|
||||||
|
|
||||||
//LDR(2) three register
|
|
||||||
if((inst & 0xFE00) == 0x5800) return Op::ldr2;
|
|
||||||
|
|
||||||
//LDR(3)
|
|
||||||
if((inst & 0xF800) == 0x4800) return Op::ldr3;
|
|
||||||
|
|
||||||
//LDR(4)
|
|
||||||
if((inst & 0xF800) == 0x9800) return Op::ldr4;
|
|
||||||
|
|
||||||
//LDRB(1)
|
|
||||||
if((inst & 0xF800) == 0x7800) return Op::ldrb1;
|
|
||||||
|
|
||||||
//LDRB(2)
|
|
||||||
if((inst & 0xFE00) == 0x5C00) return Op::ldrb2;
|
|
||||||
|
|
||||||
//LDRH(1)
|
|
||||||
if((inst & 0xF800) == 0x8800) return Op::ldrh1;
|
|
||||||
|
|
||||||
//LDRH(2)
|
|
||||||
if((inst & 0xFE00) == 0x5A00) return Op::ldrh2;
|
|
||||||
|
|
||||||
//LDRSB
|
|
||||||
if((inst & 0xFE00) == 0x5600) return Op::ldrsb;
|
|
||||||
|
|
||||||
//LDRSH
|
|
||||||
if((inst & 0xFE00) == 0x5E00) return Op::ldrsh;
|
|
||||||
|
|
||||||
//LSL(1)
|
|
||||||
if((inst & 0xF800) == 0x0000) return Op::lsl1;
|
|
||||||
|
|
||||||
//LSL(2) two register
|
|
||||||
if((inst & 0xFFC0) == 0x4080) return Op::lsl2;
|
|
||||||
|
|
||||||
//LSR(1) two register immediate
|
|
||||||
if((inst & 0xF800) == 0x0800) return Op::lsr1;
|
|
||||||
|
|
||||||
//LSR(2) two register
|
|
||||||
if((inst & 0xFFC0) == 0x40C0) return Op::lsr2;
|
|
||||||
|
|
||||||
//MOV(1) immediate
|
|
||||||
if((inst & 0xF800) == 0x2000) return Op::mov1;
|
|
||||||
|
|
||||||
//MOV(2) two low registers
|
|
||||||
if((inst & 0xFFC0) == 0x1C00) return Op::mov2;
|
|
||||||
|
|
||||||
//MOV(3)
|
|
||||||
if((inst & 0xFF00) == 0x4600) return Op::mov3;
|
|
||||||
|
|
||||||
//MUL
|
|
||||||
if((inst & 0xFFC0) == 0x4340) return Op::mul;
|
|
||||||
|
|
||||||
//MVN
|
|
||||||
if((inst & 0xFFC0) == 0x43C0) return Op::mvn;
|
|
||||||
|
|
||||||
//NEG
|
|
||||||
if((inst & 0xFFC0) == 0x4240) return Op::neg;
|
|
||||||
|
|
||||||
//ORR
|
|
||||||
if((inst & 0xFFC0) == 0x4300) return Op::orr;
|
|
||||||
|
|
||||||
//POP
|
|
||||||
if((inst & 0xFE00) == 0xBC00) return Op::pop;
|
|
||||||
|
|
||||||
//PUSH
|
|
||||||
if((inst & 0xFE00) == 0xB400) return Op::push;
|
|
||||||
|
|
||||||
//REV
|
|
||||||
if((inst & 0xFFC0) == 0xBA00) return Op::rev;
|
|
||||||
|
|
||||||
//REV16
|
|
||||||
if((inst & 0xFFC0) == 0xBA40) return Op::rev16;
|
|
||||||
|
|
||||||
//REVSH
|
|
||||||
if((inst & 0xFFC0) == 0xBAC0) return Op::revsh;
|
|
||||||
|
|
||||||
//ROR
|
|
||||||
if((inst & 0xFFC0) == 0x41C0) return Op::ror;
|
|
||||||
|
|
||||||
//SBC
|
|
||||||
if((inst & 0xFFC0) == 0x4180) return Op::sbc;
|
|
||||||
|
|
||||||
//SETEND
|
|
||||||
if((inst & 0xFFF7) == 0xB650) return Op::setend;
|
|
||||||
|
|
||||||
//STMIA
|
|
||||||
if((inst & 0xF800) == 0xC000) return Op::stmia;
|
|
||||||
|
|
||||||
//STR(1)
|
|
||||||
if((inst & 0xF800) == 0x6000) return Op::str1;
|
|
||||||
|
|
||||||
//STR(2)
|
|
||||||
if((inst & 0xFE00) == 0x5000) return Op::str2;
|
|
||||||
|
|
||||||
//STR(3)
|
|
||||||
if((inst & 0xF800) == 0x9000) return Op::str3;
|
|
||||||
|
|
||||||
//STRB(1)
|
|
||||||
if((inst & 0xF800) == 0x7000) return Op::strb1;
|
|
||||||
|
|
||||||
//STRB(2)
|
|
||||||
if((inst & 0xFE00) == 0x5400) return Op::strb2;
|
|
||||||
|
|
||||||
//STRH(1)
|
|
||||||
if((inst & 0xF800) == 0x8000) return Op::strh1;
|
|
||||||
|
|
||||||
//STRH(2)
|
|
||||||
if((inst & 0xFE00) == 0x5200) return Op::strh2;
|
|
||||||
|
|
||||||
//SUB(1)
|
|
||||||
if((inst & 0xFE00) == 0x1E00) return Op::sub1;
|
|
||||||
|
|
||||||
//SUB(2)
|
|
||||||
if((inst & 0xF800) == 0x3800) return Op::sub2;
|
|
||||||
|
|
||||||
//SUB(3)
|
|
||||||
if((inst & 0xFE00) == 0x1A00) return Op::sub3;
|
|
||||||
|
|
||||||
//SUB(4)
|
|
||||||
if((inst & 0xFF80) == 0xB080) return Op::sub4;
|
|
||||||
|
|
||||||
//SWI SoftWare Interupt
|
|
||||||
if((inst & 0xFF00) == 0xDF00) return Op::swi;
|
|
||||||
|
|
||||||
//SXTB
|
|
||||||
if((inst & 0xFFC0) == 0xB240) return Op::sxtb;
|
|
||||||
|
|
||||||
//SXTH
|
|
||||||
if((inst & 0xFFC0) == 0xB200) return Op::sxth;
|
|
||||||
|
|
||||||
//TST
|
|
||||||
if((inst & 0xFFC0) == 0x4200) return Op::tst;
|
|
||||||
|
|
||||||
//UXTB
|
|
||||||
if((inst & 0xFFC0) == 0xB2C0) return Op::uxtb;
|
|
||||||
|
|
||||||
//UXTH Zero extend Halfword
|
|
||||||
if((inst & 0xFFC0) == 0xB280) return Op::uxth;
|
|
||||||
|
|
||||||
|
//BL/BLX(1) decoded into its variants
|
||||||
|
if((inst & 0xE000) == 0xE000)
|
||||||
|
{
|
||||||
|
if((inst & 0x1800) == 0x1000) return Op::bl;
|
||||||
|
else if((inst & 0x1800) == 0x1800) return Op::blx_thumb;
|
||||||
return Op::invalid;
|
return Op::invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//BLX(2)
|
||||||
|
if((inst & 0xFF87) == 0x4780) return Op::blx2;
|
||||||
|
|
||||||
|
//BX
|
||||||
|
if((inst & 0xFF87) == 0x4700) return Op::bx;
|
||||||
|
|
||||||
|
//CMN
|
||||||
|
if((inst & 0xFFC0) == 0x42C0) return Op::cmn;
|
||||||
|
|
||||||
|
//CMP(1) compare immediate
|
||||||
|
if((inst & 0xF800) == 0x2800) return Op::cmp1;
|
||||||
|
|
||||||
|
//CMP(2) compare register
|
||||||
|
if((inst & 0xFFC0) == 0x4280) return Op::cmp2;
|
||||||
|
|
||||||
|
//CMP(3) compare high register
|
||||||
|
if((inst & 0xFF00) == 0x4500) return Op::cmp3;
|
||||||
|
|
||||||
|
//CPY copy high register
|
||||||
|
if((inst & 0xFFC0) == 0x4600) return Op::cpy;
|
||||||
|
|
||||||
|
//EOR
|
||||||
|
if((inst & 0xFFC0) == 0x4040) return Op::eor;
|
||||||
|
|
||||||
|
//LDMIA
|
||||||
|
if((inst & 0xF800) == 0xC800) return Op::ldmia;
|
||||||
|
|
||||||
|
//LDR(1) two register immediate
|
||||||
|
if((inst & 0xF800) == 0x6800) return Op::ldr1;
|
||||||
|
|
||||||
|
//LDR(2) three register
|
||||||
|
if((inst & 0xFE00) == 0x5800) return Op::ldr2;
|
||||||
|
|
||||||
|
//LDR(3)
|
||||||
|
if((inst & 0xF800) == 0x4800) return Op::ldr3;
|
||||||
|
|
||||||
|
//LDR(4)
|
||||||
|
if((inst & 0xF800) == 0x9800) return Op::ldr4;
|
||||||
|
|
||||||
|
//LDRB(1)
|
||||||
|
if((inst & 0xF800) == 0x7800) return Op::ldrb1;
|
||||||
|
|
||||||
|
//LDRB(2)
|
||||||
|
if((inst & 0xFE00) == 0x5C00) return Op::ldrb2;
|
||||||
|
|
||||||
|
//LDRH(1)
|
||||||
|
if((inst & 0xF800) == 0x8800) return Op::ldrh1;
|
||||||
|
|
||||||
|
//LDRH(2)
|
||||||
|
if((inst & 0xFE00) == 0x5A00) return Op::ldrh2;
|
||||||
|
|
||||||
|
//LDRSB
|
||||||
|
if((inst & 0xFE00) == 0x5600) return Op::ldrsb;
|
||||||
|
|
||||||
|
//LDRSH
|
||||||
|
if((inst & 0xFE00) == 0x5E00) return Op::ldrsh;
|
||||||
|
|
||||||
|
//LSL(1)
|
||||||
|
if((inst & 0xF800) == 0x0000) return Op::lsl1;
|
||||||
|
|
||||||
|
//LSL(2) two register
|
||||||
|
if((inst & 0xFFC0) == 0x4080) return Op::lsl2;
|
||||||
|
|
||||||
|
//LSR(1) two register immediate
|
||||||
|
if((inst & 0xF800) == 0x0800) return Op::lsr1;
|
||||||
|
|
||||||
|
//LSR(2) two register
|
||||||
|
if((inst & 0xFFC0) == 0x40C0) return Op::lsr2;
|
||||||
|
|
||||||
|
//MOV(1) immediate
|
||||||
|
if((inst & 0xF800) == 0x2000) return Op::mov1;
|
||||||
|
|
||||||
|
//MOV(2) two low registers
|
||||||
|
if((inst & 0xFFC0) == 0x1C00) return Op::mov2;
|
||||||
|
|
||||||
|
//MOV(3)
|
||||||
|
if((inst & 0xFF00) == 0x4600) return Op::mov3;
|
||||||
|
|
||||||
|
//MUL
|
||||||
|
if((inst & 0xFFC0) == 0x4340) return Op::mul;
|
||||||
|
|
||||||
|
//MVN
|
||||||
|
if((inst & 0xFFC0) == 0x43C0) return Op::mvn;
|
||||||
|
|
||||||
|
//NEG
|
||||||
|
if((inst & 0xFFC0) == 0x4240) return Op::neg;
|
||||||
|
|
||||||
|
//ORR
|
||||||
|
if((inst & 0xFFC0) == 0x4300) return Op::orr;
|
||||||
|
|
||||||
|
//POP
|
||||||
|
if((inst & 0xFE00) == 0xBC00) return Op::pop;
|
||||||
|
|
||||||
|
//PUSH
|
||||||
|
if((inst & 0xFE00) == 0xB400) return Op::push;
|
||||||
|
|
||||||
|
//REV
|
||||||
|
if((inst & 0xFFC0) == 0xBA00) return Op::rev;
|
||||||
|
|
||||||
|
//REV16
|
||||||
|
if((inst & 0xFFC0) == 0xBA40) return Op::rev16;
|
||||||
|
|
||||||
|
//REVSH
|
||||||
|
if((inst & 0xFFC0) == 0xBAC0) return Op::revsh;
|
||||||
|
|
||||||
|
//ROR
|
||||||
|
if((inst & 0xFFC0) == 0x41C0) return Op::ror;
|
||||||
|
|
||||||
|
//SBC
|
||||||
|
if((inst & 0xFFC0) == 0x4180) return Op::sbc;
|
||||||
|
|
||||||
|
//SETEND
|
||||||
|
if((inst & 0xFFF7) == 0xB650) return Op::setend;
|
||||||
|
|
||||||
|
//STMIA
|
||||||
|
if((inst & 0xF800) == 0xC000) return Op::stmia;
|
||||||
|
|
||||||
|
//STR(1)
|
||||||
|
if((inst & 0xF800) == 0x6000) return Op::str1;
|
||||||
|
|
||||||
|
//STR(2)
|
||||||
|
if((inst & 0xFE00) == 0x5000) return Op::str2;
|
||||||
|
|
||||||
|
//STR(3)
|
||||||
|
if((inst & 0xF800) == 0x9000) return Op::str3;
|
||||||
|
|
||||||
|
//STRB(1)
|
||||||
|
if((inst & 0xF800) == 0x7000) return Op::strb1;
|
||||||
|
|
||||||
|
//STRB(2)
|
||||||
|
if((inst & 0xFE00) == 0x5400) return Op::strb2;
|
||||||
|
|
||||||
|
//STRH(1)
|
||||||
|
if((inst & 0xF800) == 0x8000) return Op::strh1;
|
||||||
|
|
||||||
|
//STRH(2)
|
||||||
|
if((inst & 0xFE00) == 0x5200) return Op::strh2;
|
||||||
|
|
||||||
|
//SUB(1)
|
||||||
|
if((inst & 0xFE00) == 0x1E00) return Op::sub1;
|
||||||
|
|
||||||
|
//SUB(2)
|
||||||
|
if((inst & 0xF800) == 0x3800) return Op::sub2;
|
||||||
|
|
||||||
|
//SUB(3)
|
||||||
|
if((inst & 0xFE00) == 0x1A00) return Op::sub3;
|
||||||
|
|
||||||
|
//SUB(4)
|
||||||
|
if((inst & 0xFF80) == 0xB080) return Op::sub4;
|
||||||
|
|
||||||
|
//SWI SoftWare Interupt
|
||||||
|
if((inst & 0xFF00) == 0xDF00) return Op::swi;
|
||||||
|
|
||||||
|
//SXTB
|
||||||
|
if((inst & 0xFFC0) == 0xB240) return Op::sxtb;
|
||||||
|
|
||||||
|
//SXTH
|
||||||
|
if((inst & 0xFFC0) == 0xB200) return Op::sxth;
|
||||||
|
|
||||||
|
//TST
|
||||||
|
if((inst & 0xFFC0) == 0x4200) return Op::tst;
|
||||||
|
|
||||||
|
//UXTB
|
||||||
|
if((inst & 0xFFC0) == 0xB2C0) return Op::uxtb;
|
||||||
|
|
||||||
|
//UXTH Zero extend Halfword
|
||||||
|
if((inst & 0xFFC0) == 0xB280) return Op::uxth;
|
||||||
|
|
||||||
|
return Op::invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
string describeErrorCode(CortexM0::err_t err) {
|
||||||
|
if (CortexM0::isErrCustom(err)) {
|
||||||
|
ostringstream s;
|
||||||
|
s << "custom error " << CortexM0::getErrCustom(err);
|
||||||
|
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (CortexM0::getErrInstrinsic(err)) {
|
||||||
|
case CortexM0::ERR_UNMAPPED_READ32:
|
||||||
|
return "unmapped read32";
|
||||||
|
|
||||||
|
case CortexM0::ERR_UNMAPPED_READ16:
|
||||||
|
return "unmapped read16";
|
||||||
|
|
||||||
|
case CortexM0::ERR_UNMAPPED_READ8:
|
||||||
|
return "unmapped read8";
|
||||||
|
|
||||||
|
case CortexM0::ERR_UNMAPPED_WRITE32:
|
||||||
|
return "unmapped write32";
|
||||||
|
|
||||||
|
case CortexM0::ERR_UNMAPPED_WRITE16:
|
||||||
|
return "unmapped write16";
|
||||||
|
|
||||||
|
case CortexM0::ERR_UNMAPPED_WRITE8:
|
||||||
|
return "unmapped write8";
|
||||||
|
|
||||||
|
case CortexM0::ERR_UNMAPPED_FETCH16:
|
||||||
|
return "unmapped fetch";
|
||||||
|
|
||||||
|
case CortexM0::ERR_WRITE_ACCESS_DENIED:
|
||||||
|
return "write access denied";
|
||||||
|
|
||||||
|
case CortexM0::ERR_ACCESS_ALIGNMENT_FAULT:
|
||||||
|
return "alignment fault";
|
||||||
|
|
||||||
|
case CortexM0::ERR_BKPT:
|
||||||
|
return "breakpoint encountered";
|
||||||
|
|
||||||
|
case CortexM0::ERR_INVALID_OPERATING_MODE:
|
||||||
|
return "invalid operation mode";
|
||||||
|
|
||||||
|
case CortexM0::ERR_UNIMPLEMENTED_INST:
|
||||||
|
return "instruction not implemented";
|
||||||
|
|
||||||
|
case CortexM0::ERR_SWI:
|
||||||
|
return "supervisor call";
|
||||||
|
|
||||||
|
case CortexM0::ERR_UNDEFINED_INST:
|
||||||
|
return "undefined instruction";
|
||||||
|
}
|
||||||
|
|
||||||
|
ostringstream s;
|
||||||
|
s << "unknown instrinsic error " << CortexM0::getErrInstrinsic(err);
|
||||||
|
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CortexM0::err_t CortexM0::BusTransactionDelegate::read32(uInt32 address, uInt32& value, CortexM0& cortex)
|
CortexM0::err_t CortexM0::BusTransactionDelegate::read32(uInt32 address, uInt32& value, CortexM0& cortex)
|
||||||
|
@ -454,6 +512,19 @@ CortexM0::err_t CortexM0::BusTransactionDelegate::fetch16(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string CortexM0::describeError(err_t err) {
|
||||||
|
if (err == ERR_NONE) return "no error";
|
||||||
|
|
||||||
|
ostringstream s;
|
||||||
|
s
|
||||||
|
<< describeErrorCode(err) << " : 0x"
|
||||||
|
<< std::hex << std::setw(8) << std::setfill('0')
|
||||||
|
<< getErrExtra(err);
|
||||||
|
|
||||||
|
return s.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CortexM0::CortexM0()
|
CortexM0::CortexM0()
|
||||||
{
|
{
|
||||||
myPageMap = make_unique<uInt8[]>(PAGEMAP_SIZE);
|
myPageMap = make_unique<uInt8[]>(PAGEMAP_SIZE);
|
||||||
|
|
|
@ -71,6 +71,10 @@ class CortexM0
|
||||||
return (err & 0xffffffff) >> 8;
|
return (err & 0xffffffff) >> 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uInt8 getErrInstrinsic(err_t err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static inline uInt32 getErrExtra(err_t err) {
|
static inline uInt32 getErrExtra(err_t err) {
|
||||||
return err >> 32;
|
return err >> 32;
|
||||||
}
|
}
|
||||||
|
@ -83,6 +87,8 @@ class CortexM0
|
||||||
return static_cast<uInt64>(code) | (static_cast<uInt64>(extra) << 32);
|
return static_cast<uInt64>(code) | (static_cast<uInt64>(extra) << 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static string describeError(err_t error);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CortexM0();
|
CortexM0();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue