mirror of https://github.com/bsnes-emu/bsnes.git
Update to v094r30 release.
byuu says: This WIP does substantially better on endrift's GBA timing tests. Still not perfect, though. But hopefully enough to get me out of dead last place. I also finally fixed the THUMB-mode ldmia bug that jchadwick reported. So, GBA emulation should be improved quite a bit, hopefully.
This commit is contained in:
parent
83f684c66c
commit
310ff4fa3b
|
@ -8,7 +8,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "094.29";
|
||||
static const string Version = "094.30";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -76,12 +76,12 @@ void CPU::bus_idle(uint32 addr) {
|
|||
}
|
||||
|
||||
uint32 CPU::bus_read(uint32 addr, uint32 size) {
|
||||
step(bus.speed(addr, size));
|
||||
step(bus.wait(addr, size));
|
||||
return bus.read(addr, size);
|
||||
}
|
||||
|
||||
void CPU::bus_write(uint32 addr, uint32 size, uint32 word) {
|
||||
step(bus.speed(addr, size));
|
||||
step(bus.wait(addr, size));
|
||||
return bus.write(addr, size, word);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@ void CPU::dma_transfer(Registers::DMA& dma) {
|
|||
|
||||
sequential() = false;
|
||||
do {
|
||||
step(bus.speed(dma.run.source, size));
|
||||
step(bus.wait(dma.run.source, size));
|
||||
uint32 word = bus.read(dma.run.source, size);
|
||||
|
||||
step(bus.speed(dma.run.target, size));
|
||||
step(bus.wait(dma.run.target, size));
|
||||
bus.write(dma.run.target, size, word);
|
||||
|
||||
sequential() = true;
|
||||
|
|
|
@ -150,7 +150,7 @@ struct Registers {
|
|||
|
||||
struct WaitControl {
|
||||
uint2 nwait[4];
|
||||
uint2 swait[4];
|
||||
uint1 swait[4];
|
||||
uint2 phi;
|
||||
uint1 prefetch;
|
||||
uint1 gametype;
|
||||
|
|
|
@ -7,13 +7,13 @@ namespace GameBoyAdvance {
|
|||
Bus bus;
|
||||
|
||||
struct UnmappedMemory : Memory {
|
||||
uint32 read(uint32 addr, uint32 size) { return 0u; }
|
||||
void write(uint32 addr, uint32 size, uint32 word) {}
|
||||
auto read(uint32 addr, uint32 size) -> uint32 { return 0; }
|
||||
auto write(uint32 addr, uint32 size, uint32 word) -> void {}
|
||||
};
|
||||
|
||||
static UnmappedMemory unmappedMemory;
|
||||
|
||||
uint32 Bus::mirror(uint32 addr, uint32 size) {
|
||||
auto Bus::mirror(uint32 addr, uint32 size) -> uint32 {
|
||||
uint32 base = 0;
|
||||
if(size) {
|
||||
uint32 mask = 1 << 27; //28-bit bus
|
||||
|
@ -31,46 +31,46 @@ uint32 Bus::mirror(uint32 addr, uint32 size) {
|
|||
return base;
|
||||
}
|
||||
|
||||
uint32 Bus::speed(uint32 addr, uint32 size) {
|
||||
if(addr & 0x08000000) {
|
||||
static unsigned timing[] = {5, 4, 3, 9};
|
||||
auto Bus::wait(uint32 addr, uint32 size) -> unsigned {
|
||||
switch(addr & 0x0f000000) {
|
||||
case 0x00000000: return 1;
|
||||
case 0x01000000: return 1;
|
||||
case 0x02000000: return (16 - cpu.regs.memory.control.ewramwait) * (size == Word ? 2 : 1);
|
||||
case 0x03000000: return 1;
|
||||
case 0x04000000: return 2;
|
||||
case 0x05000000: return 1 + (size == Word);
|
||||
case 0x06000000: return 1 + (size == Word);
|
||||
case 0x07000000: return 1;
|
||||
default: {
|
||||
unsigned n = cpu.regs.wait.control.nwait[addr >> 25 & 3];
|
||||
unsigned s = cpu.regs.wait.control.swait[addr >> 25 & 3];
|
||||
|
||||
static unsigned timing[] = {5, 4, 3, 9};
|
||||
n = timing[n];
|
||||
|
||||
switch(addr >> 25 & 3) {
|
||||
case 0: s = s ? 3 : 2; break;
|
||||
case 1: s = s ? 5 : 2; break;
|
||||
case 2: s = s ? 9 : 2; break;
|
||||
case 3: s = n; break;
|
||||
switch(addr & 0x0e000000) {
|
||||
case 0x08000000: s = s ? 2 : 3; break;
|
||||
case 0x0a000000: s = s ? 2 : 5; break;
|
||||
case 0x0c000000: s = s ? 2 : 9; break;
|
||||
case 0x0e000000: s = n; break;
|
||||
}
|
||||
|
||||
bool sequential = cpu.sequential();
|
||||
if((addr & 0xffff << 1) == 0) sequential = false; //N cycle on 16-bit ROM crossing page boundary (RAM S==N)
|
||||
if((addr & 0x1fffe) == 0) sequential = false; //N cycle on 16-bit ROM crossing 128KB page boundary (RAM S==N)
|
||||
if(idleflag) sequential = false; //LDR/LDM interrupts instruction fetches
|
||||
|
||||
if(sequential) return s << (size == Word); //16-bit bus requires two transfers for words
|
||||
if(size == Word) n += s;
|
||||
return n;
|
||||
unsigned clocks = sequential ? s : n;
|
||||
if(size == Word) clocks += s; //16-bit bus requires two transfers for words
|
||||
return clocks;
|
||||
}
|
||||
|
||||
switch(addr >> 24 & 7) {
|
||||
case 0: return 1;
|
||||
case 1: return 1;
|
||||
case 2: return (1 + 15 - cpu.regs.memory.control.ewramwait) << (size == Word);
|
||||
case 3: return 1;
|
||||
case 4: return 1;
|
||||
case 5: return 1 << (size == Word);
|
||||
case 6: return 1 << (size == Word);
|
||||
case 7: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Bus::idle(uint32 addr) {
|
||||
auto Bus::idle(uint32 addr) -> void {
|
||||
if(addr & 0x08000000) idleflag = true;
|
||||
}
|
||||
|
||||
uint32 Bus::read(uint32 addr, uint32 size) {
|
||||
auto Bus::read(uint32 addr, uint32 size) -> uint32 {
|
||||
idleflag = false;
|
||||
if(addr & 0x08000000) return cartridge.read(addr, size);
|
||||
|
||||
|
@ -89,7 +89,7 @@ uint32 Bus::read(uint32 addr, uint32 size) {
|
|||
}
|
||||
}
|
||||
|
||||
void Bus::write(uint32 addr, uint32 size, uint32 word) {
|
||||
auto Bus::write(uint32 addr, uint32 size, uint32 word) -> void {
|
||||
idleflag = false;
|
||||
if(addr & 0x08000000) return cartridge.write(addr, size, word);
|
||||
|
||||
|
@ -108,7 +108,7 @@ void Bus::write(uint32 addr, uint32 size, uint32 word) {
|
|||
}
|
||||
}
|
||||
|
||||
void Bus::power() {
|
||||
auto Bus::power() -> void {
|
||||
for(unsigned n = 0; n < 0x400; n++) mmio[n] = &unmappedMemory;
|
||||
idleflag = false;
|
||||
}
|
||||
|
|
|
@ -1,27 +1,28 @@
|
|||
struct Memory {
|
||||
virtual uint32 read(uint32 addr, uint32 size) = 0;
|
||||
virtual void write(uint32 addr, uint32 size, uint32 word) = 0;
|
||||
virtual auto read(uint32 addr, uint32 size) -> uint32 = 0;
|
||||
virtual auto write(uint32 addr, uint32 size, uint32 word) -> void = 0;
|
||||
};
|
||||
|
||||
struct MMIO : Memory {
|
||||
virtual uint8 read(uint32 addr) = 0;
|
||||
virtual void write(uint32 addr, uint8 data) = 0;
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
virtual auto read(uint32 addr) -> uint8 = 0;
|
||||
virtual auto write(uint32 addr, uint8 data) -> void = 0;
|
||||
auto read(uint32 addr, uint32 size) -> uint32;
|
||||
auto write(uint32 addr, uint32 size, uint32 word) -> void;
|
||||
};
|
||||
|
||||
struct Bus : Memory {
|
||||
Memory* mmio[0x400];
|
||||
bool idleflag;
|
||||
static uint32 mirror(uint32 addr, uint32 size);
|
||||
static auto mirror(uint32 addr, uint32 size) -> uint32;
|
||||
|
||||
uint32 speed(uint32 addr, uint32 size);
|
||||
void idle(uint32 addr);
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
void power();
|
||||
auto wait(uint32 addr, uint32 size) -> unsigned;
|
||||
auto idle(uint32 addr) -> void;
|
||||
auto read(uint32 addr, uint32 size) -> uint32;
|
||||
auto write(uint32 addr, uint32 size, uint32 word) -> void;
|
||||
auto power() -> void;
|
||||
|
||||
void serialize(serializer&);
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
Memory* mmio[0x400]{nullptr};
|
||||
bool idleflag{false};
|
||||
};
|
||||
|
||||
extern Bus bus;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
uint32 MMIO::read(uint32 addr, uint32 size) {
|
||||
auto MMIO::read(uint32 addr, uint32 size) -> uint32 {
|
||||
uint32 word = 0;
|
||||
|
||||
switch(size) {
|
||||
|
@ -22,7 +22,7 @@ uint32 MMIO::read(uint32 addr, uint32 size) {
|
|||
return word;
|
||||
}
|
||||
|
||||
void MMIO::write(uint32 addr, uint32 size, uint32 word) {
|
||||
auto MMIO::write(uint32 addr, uint32 size, uint32 word) -> void {
|
||||
switch(size) {
|
||||
case Word:
|
||||
addr &= ~3;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
void Bus::serialize(serializer& s) {
|
||||
auto Bus::serialize(serializer& s) -> void {
|
||||
s.integer(idleflag);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace nall {
|
|||
#if defined(_WIN32)
|
||||
#define PLATFORM_WINDOWS
|
||||
#define API_WINDOWS
|
||||
#define DISPLAY_WINDOW
|
||||
#define DISPLAY_WINDOWS
|
||||
auto Intrinsics::platform() -> Platform { return Platform::Windows; }
|
||||
auto Intrinsics::api() -> API { return API::Windows; }
|
||||
auto Intrinsics::display() -> Display { return Display::Windows; }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
bool ARM::condition(uint4 condition) {
|
||||
auto ARM::condition(uint4 condition) -> bool {
|
||||
switch(condition) {
|
||||
case 0: return cpsr().z == 1; //EQ (equal)
|
||||
case 1: return cpsr().z == 0; //NE (not equal)
|
||||
|
@ -19,7 +19,7 @@ bool ARM::condition(uint4 condition) {
|
|||
}
|
||||
}
|
||||
|
||||
uint32 ARM::bit(uint32 result) {
|
||||
auto ARM::bit(uint32 result) -> uint32 {
|
||||
if(cpsr().t || instruction() & (1 << 20)) {
|
||||
cpsr().n = result >> 31;
|
||||
cpsr().z = result == 0;
|
||||
|
@ -28,7 +28,7 @@ uint32 ARM::bit(uint32 result) {
|
|||
return result;
|
||||
}
|
||||
|
||||
uint32 ARM::add(uint32 source, uint32 modify, bool carry) {
|
||||
auto ARM::add(uint32 source, uint32 modify, bool carry) -> uint32 {
|
||||
uint32 result = source + modify + carry;
|
||||
if(cpsr().t || instruction() & (1 << 20)) {
|
||||
uint32 overflow = ~(source ^ modify) & (source ^ result);
|
||||
|
@ -40,11 +40,16 @@ uint32 ARM::add(uint32 source, uint32 modify, bool carry) {
|
|||
return result;
|
||||
}
|
||||
|
||||
uint32 ARM::sub(uint32 source, uint32 modify, bool carry) {
|
||||
auto ARM::sub(uint32 source, uint32 modify, bool carry) -> uint32 {
|
||||
return add(source, ~modify, carry);
|
||||
}
|
||||
|
||||
uint32 ARM::mul(uint32 product, uint32 multiplicand, uint32 multiplier) {
|
||||
auto ARM::mul(uint32 product, uint32 multiplicand, uint32 multiplier) -> uint32 {
|
||||
if((multiplier & 0xffffff00) == 0x00000000 || (multiplier & 0xffffff00 == 0xffffff00)) step(1);
|
||||
else if((multiplier & 0xffff0000) == 0x00000000 || (multiplier & 0xffff0000 == 0xffff0000)) step(2);
|
||||
else if((multiplier & 0xff000000) == 0x00000000 || (multiplier & 0xff000000 == 0xff000000)) step(3);
|
||||
else step(4);
|
||||
|
||||
product += multiplicand * multiplier;
|
||||
|
||||
if(cpsr().t || instruction() & (1 << 20)) {
|
||||
|
@ -55,7 +60,7 @@ uint32 ARM::mul(uint32 product, uint32 multiplicand, uint32 multiplier) {
|
|||
return product;
|
||||
}
|
||||
|
||||
uint32 ARM::lsl(uint32 source, uint8 shift) {
|
||||
auto ARM::lsl(uint32 source, uint8 shift) -> uint32 {
|
||||
carryout() = cpsr().c;
|
||||
if(shift == 0) return source;
|
||||
|
||||
|
@ -64,7 +69,7 @@ uint32 ARM::lsl(uint32 source, uint8 shift) {
|
|||
return source;
|
||||
}
|
||||
|
||||
uint32 ARM::lsr(uint32 source, uint8 shift) {
|
||||
auto ARM::lsr(uint32 source, uint8 shift) -> uint32 {
|
||||
carryout() = cpsr().c;
|
||||
if(shift == 0) return source;
|
||||
|
||||
|
@ -73,7 +78,7 @@ uint32 ARM::lsr(uint32 source, uint8 shift) {
|
|||
return source;
|
||||
}
|
||||
|
||||
uint32 ARM::asr(uint32 source, uint8 shift) {
|
||||
auto ARM::asr(uint32 source, uint8 shift) -> uint32 {
|
||||
carryout() = cpsr().c;
|
||||
if(shift == 0) return source;
|
||||
|
||||
|
@ -82,7 +87,7 @@ uint32 ARM::asr(uint32 source, uint8 shift) {
|
|||
return source;
|
||||
}
|
||||
|
||||
uint32 ARM::ror(uint32 source, uint8 shift) {
|
||||
auto ARM::ror(uint32 source, uint8 shift) -> uint32 {
|
||||
carryout() = cpsr().c;
|
||||
if(shift == 0) return source;
|
||||
|
||||
|
@ -92,7 +97,7 @@ uint32 ARM::ror(uint32 source, uint8 shift) {
|
|||
return source;
|
||||
}
|
||||
|
||||
uint32 ARM::rrx(uint32 source) {
|
||||
auto ARM::rrx(uint32 source) -> uint32 {
|
||||
carryout() = source & 1;
|
||||
return (cpsr().c << 31) | (source >> 1);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,11 @@ namespace Processor {
|
|||
#include "algorithms.cpp"
|
||||
#include "instructions-arm.cpp"
|
||||
#include "instructions-thumb.cpp"
|
||||
#include "step.cpp"
|
||||
#include "disassembler.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
void ARM::power() {
|
||||
auto ARM::power() -> void {
|
||||
processor.power();
|
||||
vector(0x00000000, Processor::Mode::SVC);
|
||||
pipeline.reload = true;
|
||||
|
@ -23,21 +24,21 @@ void ARM::power() {
|
|||
instructions = 0;
|
||||
}
|
||||
|
||||
void ARM::exec() {
|
||||
auto ARM::exec() -> void {
|
||||
cpsr().t ? thumb_step() : arm_step();
|
||||
}
|
||||
|
||||
void ARM::idle() {
|
||||
auto ARM::idle() -> void {
|
||||
bus_idle(r(15));
|
||||
}
|
||||
|
||||
uint32 ARM::read(uint32 addr, uint32 size) {
|
||||
auto ARM::read(uint32 addr, uint32 size) -> uint32 {
|
||||
uint32 word = bus_read(addr, size);
|
||||
sequential() = true;
|
||||
return word;
|
||||
}
|
||||
|
||||
uint32 ARM::load(uint32 addr, uint32 size) {
|
||||
auto ARM::load(uint32 addr, uint32 size) -> uint32 {
|
||||
sequential() = false;
|
||||
uint32 word = read(addr, size);
|
||||
|
||||
|
@ -52,12 +53,12 @@ uint32 ARM::load(uint32 addr, uint32 size) {
|
|||
return word;
|
||||
}
|
||||
|
||||
void ARM::write(uint32 addr, uint32 size, uint32 word) {
|
||||
auto ARM::write(uint32 addr, uint32 size, uint32 word) -> void {
|
||||
bus_write(addr, size, word);
|
||||
sequential() = true;
|
||||
}
|
||||
|
||||
void ARM::store(uint32 addr, uint32 size, uint32 word) {
|
||||
auto ARM::store(uint32 addr, uint32 size, uint32 word) -> void {
|
||||
if(size == Half) { word &= 0xffff; word |= word << 16; }
|
||||
if(size == Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
||||
|
||||
|
@ -66,7 +67,7 @@ void ARM::store(uint32 addr, uint32 size, uint32 word) {
|
|||
sequential() = false;
|
||||
}
|
||||
|
||||
void ARM::vector(uint32 addr, Processor::Mode mode) {
|
||||
auto ARM::vector(uint32 addr, Processor::Mode mode) -> void {
|
||||
auto psr = cpsr();
|
||||
processor.setMode(mode);
|
||||
spsr() = psr;
|
||||
|
|
|
@ -3,44 +3,54 @@
|
|||
|
||||
namespace Processor {
|
||||
|
||||
//ARMv3
|
||||
//ARMv4TDMI
|
||||
//Supported Models:
|
||||
//* ARMv3 (ST018)
|
||||
//* ARMv4 (ARM7TDMI)
|
||||
|
||||
struct ARM {
|
||||
enum : unsigned { Byte = 8, Half = 16, Word = 32 };
|
||||
|
||||
#include "registers.hpp"
|
||||
#include "instructions-arm.hpp"
|
||||
#include "instructions-thumb.hpp"
|
||||
#include "disassembler.hpp"
|
||||
virtual void step(unsigned clocks) = 0;
|
||||
virtual void bus_idle(uint32 addr) = 0;
|
||||
virtual uint32 bus_read(uint32 addr, uint32 size) = 0;
|
||||
virtual void bus_write(uint32 addr, uint32 size, uint32 word) = 0;
|
||||
|
||||
void power();
|
||||
void exec();
|
||||
void idle();
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
uint32 load(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
void store(uint32 addr, uint32 size, uint32 word);
|
||||
void vector(uint32 addr, Processor::Mode mode);
|
||||
virtual auto step(unsigned clocks) -> void = 0;
|
||||
virtual auto bus_idle(uint32 addr) -> void = 0;
|
||||
virtual auto bus_read(uint32 addr, uint32 size) -> uint32 = 0;
|
||||
virtual auto bus_write(uint32 addr, uint32 size, uint32 word) -> void = 0;
|
||||
|
||||
bool condition(uint4 condition);
|
||||
uint32 bit(uint32 result);
|
||||
uint32 add(uint32 source, uint32 modify, bool carry);
|
||||
uint32 sub(uint32 source, uint32 modify, bool carry);
|
||||
uint32 mul(uint32 product, uint32 multiplicand, uint32 multiplier);
|
||||
uint32 lsl(uint32 source, uint8 shift);
|
||||
uint32 lsr(uint32 source, uint8 shift);
|
||||
uint32 asr(uint32 source, uint8 shift);
|
||||
uint32 ror(uint32 source, uint8 shift);
|
||||
uint32 rrx(uint32 source);
|
||||
//arm.cpp
|
||||
auto power() -> void;
|
||||
auto exec() -> void;
|
||||
auto idle() -> void;
|
||||
auto read(uint32 addr, uint32 size) -> uint32;
|
||||
auto load(uint32 addr, uint32 size) -> uint32;
|
||||
auto write(uint32 addr, uint32 size, uint32 word) -> void;
|
||||
auto store(uint32 addr, uint32 size, uint32 word) -> void;
|
||||
auto vector(uint32 addr, Processor::Mode mode) -> void;
|
||||
|
||||
void serialize(serializer&);
|
||||
//algorithms.cpp
|
||||
auto condition(uint4 condition) -> bool;
|
||||
auto bit(uint32 result) -> uint32;
|
||||
auto add(uint32 source, uint32 modify, bool carry) -> uint32;
|
||||
auto sub(uint32 source, uint32 modify, bool carry) -> uint32;
|
||||
auto mul(uint32 product, uint32 multiplicand, uint32 multiplier) -> uint32;
|
||||
auto lsl(uint32 source, uint8 shift) -> uint32;
|
||||
auto lsr(uint32 source, uint8 shift) -> uint32;
|
||||
auto asr(uint32 source, uint8 shift) -> uint32;
|
||||
auto ror(uint32 source, uint8 shift) -> uint32;
|
||||
auto rrx(uint32 source) -> uint32;
|
||||
|
||||
bool trace;
|
||||
uintmax_t instructions;
|
||||
//step.cpp
|
||||
auto arm_step() -> void;
|
||||
auto thumb_step() -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool trace{false};
|
||||
uintmax_t instructions{0};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef PROCESSOR_ARM_HPP
|
||||
|
||||
string ARM::disassemble_arm_instruction(uint32 pc) {
|
||||
auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
||||
static string conditions[] = {
|
||||
"eq", "ne", "cs", "cc",
|
||||
"mi", "pl", "vs", "vc",
|
||||
|
@ -440,7 +440,7 @@ string ARM::disassemble_arm_instruction(uint32 pc) {
|
|||
return output;
|
||||
}
|
||||
|
||||
string ARM::disassemble_thumb_instruction(uint32 pc) {
|
||||
auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
||||
static string conditions[] = {
|
||||
"eq", "ne", "cs", "cc",
|
||||
"mi", "pl", "vs", "vc",
|
||||
|
@ -761,7 +761,7 @@ string ARM::disassemble_thumb_instruction(uint32 pc) {
|
|||
return output;
|
||||
}
|
||||
|
||||
string ARM::disassemble_registers() {
|
||||
auto ARM::disassemble_registers() -> string {
|
||||
string output;
|
||||
output.append( "r0:", hex<8>(r( 0)), " r1:", hex<8>(r( 1)), " r2:", hex<8>(r( 2)), " r3:", hex<8>(r( 3)), " ");
|
||||
output.append( "r4:", hex<8>(r( 4)), " r5:", hex<8>(r( 5)), " r6:", hex<8>(r( 6)), " r7:", hex<8>(r( 7)), " ");
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
string disassemble_arm_instruction(uint32 pc);
|
||||
string disassemble_thumb_instruction(uint32 pc);
|
||||
string disassemble_registers();
|
||||
auto disassemble_arm_instruction(uint32 pc) -> string;
|
||||
auto disassemble_thumb_instruction(uint32 pc) -> string;
|
||||
auto disassemble_registers() -> string;
|
||||
|
|
|
@ -1,64 +1,6 @@
|
|||
#ifdef PROCESSOR_ARM_HPP
|
||||
|
||||
void ARM::arm_step() {
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
r(15).data &= ~3;
|
||||
|
||||
sequential() = false;
|
||||
pipeline.fetch.address = r(15) & ~3;
|
||||
pipeline.fetch.instruction = read(pipeline.fetch.address, Word);
|
||||
|
||||
pipeline_step();
|
||||
}
|
||||
|
||||
pipeline_step();
|
||||
|
||||
if(processor.irqline && cpsr().i == 0) {
|
||||
vector(0x00000018, Processor::Mode::IRQ);
|
||||
return;
|
||||
}
|
||||
|
||||
instructions++;
|
||||
if(trace) {
|
||||
print(disassemble_registers(), "\n");
|
||||
print(disassemble_arm_instruction(pipeline.execute.address), "\n");
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
if(condition(instruction() >> 28) == false) return;
|
||||
|
||||
#define decode(pattern, execute) if( \
|
||||
(instruction() & std::integral_constant<uint32, bit::mask(pattern)>::value) \
|
||||
== std::integral_constant<uint32, bit::test(pattern)>::value \
|
||||
) return arm_op_ ## execute()
|
||||
|
||||
decode("???? 0001 0010 ++++ ++++ ++++ 0001 ????", branch_exchange_register);
|
||||
decode("???? 0000 00?? ???? ???? ???? 1001 ????", multiply);
|
||||
decode("???? 0000 1??? ???? ???? ???? 1001 ????", multiply_long);
|
||||
decode("???? 0001 0?00 ++++ ???? ---- 0000 ----", move_to_register_from_status);
|
||||
decode("???? 0001 0?00 ???? ???? ---- 1001 ????", memory_swap);
|
||||
decode("???? 0001 0?10 ???? ++++ ---- 0000 ????", move_to_status_from_register);
|
||||
decode("???? 0011 0?10 ???? ++++ ???? ???? ????", move_to_status_from_immediate);
|
||||
decode("???? 000? ?0?1 ???? ???? ---- 11?1 ????", load_register);
|
||||
decode("???? 000? ?1?1 ???? ???? ???? 11?1 ????", load_immediate);
|
||||
decode("???? 000? ?0?? ???? ???? ---- 1011 ????", move_half_register);
|
||||
decode("???? 000? ?1?? ???? ???? ???? 1011 ????", move_half_immediate);
|
||||
decode("???? 000? ???? ???? ???? ???? ???0 ????", data_immediate_shift);
|
||||
decode("???? 000? ???? ???? ???? ???? 0??1 ????", data_register_shift);
|
||||
decode("???? 001? ???? ???? ???? ???? ???? ????", data_immediate);
|
||||
decode("???? 010? ???? ???? ???? ???? ???? ????", move_immediate_offset);
|
||||
decode("???? 011? ???? ???? ???? ???? ???0 ????", move_register_offset);
|
||||
decode("???? 100? ???? ???? ???? ???? ???? ????", move_multiple);
|
||||
decode("???? 101? ???? ???? ???? ???? ???? ????", branch);
|
||||
decode("???? 1111 ???? ???? ???? ???? ???? ????", software_interrupt);
|
||||
|
||||
#undef decode
|
||||
|
||||
crash = true;
|
||||
}
|
||||
|
||||
void ARM::arm_opcode(uint32 rm) {
|
||||
auto ARM::arm_opcode(uint32 rm) {
|
||||
uint4 opcode = instruction() >> 21;
|
||||
uint1 save = instruction() >> 20;
|
||||
uint4 n = instruction() >> 16;
|
||||
|
@ -91,7 +33,7 @@ void ARM::arm_opcode(uint32 rm) {
|
|||
}
|
||||
}
|
||||
|
||||
void ARM::arm_move_to_status(uint32 rm) {
|
||||
auto ARM::arm_move_to_status(uint32 rm) {
|
||||
uint1 source = instruction() >> 22;
|
||||
uint4 field = instruction() >> 16;
|
||||
|
||||
|
@ -130,7 +72,7 @@ void ARM::arm_move_to_status(uint32 rm) {
|
|||
//n = rn
|
||||
//s = rs
|
||||
//m = rm
|
||||
void ARM::arm_op_multiply() {
|
||||
auto ARM::arm_op_multiply() {
|
||||
uint1 accumulate = instruction() >> 21;
|
||||
uint1 save = instruction() >> 20;
|
||||
uint4 d = instruction() >> 16;
|
||||
|
@ -138,7 +80,6 @@ void ARM::arm_op_multiply() {
|
|||
uint4 s = instruction() >> 8;
|
||||
uint4 m = instruction();
|
||||
|
||||
step(1);
|
||||
r(d) = mul(accumulate ? r(n) : 0u, r(m), r(s));
|
||||
}
|
||||
|
||||
|
@ -153,7 +94,7 @@ void ARM::arm_op_multiply() {
|
|||
//l = rdlo
|
||||
//s = rs
|
||||
//m = rm
|
||||
void ARM::arm_op_multiply_long() {
|
||||
auto ARM::arm_op_multiply_long() {
|
||||
uint1 signextend = instruction() >> 22;
|
||||
uint1 accumulate = instruction() >> 21;
|
||||
uint1 save = instruction() >> 20;
|
||||
|
@ -190,7 +131,7 @@ void ARM::arm_op_multiply_long() {
|
|||
//n = rn
|
||||
//d = rd
|
||||
//m = rm
|
||||
void ARM::arm_op_memory_swap() {
|
||||
auto ARM::arm_op_memory_swap() {
|
||||
uint1 byte = instruction() >> 22;
|
||||
uint4 n = instruction() >> 16;
|
||||
uint4 d = instruction() >> 12;
|
||||
|
@ -212,7 +153,7 @@ void ARM::arm_op_memory_swap() {
|
|||
//n = rn
|
||||
//d = rd
|
||||
//m = rm
|
||||
void ARM::arm_op_move_half_register() {
|
||||
auto ARM::arm_op_move_half_register() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 writeback = instruction() >> 21;
|
||||
|
@ -244,7 +185,7 @@ void ARM::arm_op_move_half_register() {
|
|||
//d = rd
|
||||
//i = immediate hi
|
||||
//i = immediate lo
|
||||
void ARM::arm_op_move_half_immediate() {
|
||||
auto ARM::arm_op_move_half_immediate() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 writeback = instruction() >> 21;
|
||||
|
@ -276,7 +217,7 @@ void ARM::arm_op_move_half_immediate() {
|
|||
//d = rd
|
||||
//h = half (0 = byte)
|
||||
//m = rm
|
||||
void ARM::arm_op_load_register() {
|
||||
auto ARM::arm_op_load_register() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 writeback = instruction() >> 21;
|
||||
|
@ -308,7 +249,7 @@ void ARM::arm_op_load_register() {
|
|||
//i = immediate hi
|
||||
//h = half (0 = byte)
|
||||
//i = immediate lo
|
||||
void ARM::arm_op_load_immediate() {
|
||||
auto ARM::arm_op_load_immediate() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 writeback = instruction() >> 21;
|
||||
|
@ -334,7 +275,7 @@ void ARM::arm_op_load_immediate() {
|
|||
//c = condition
|
||||
//r = SPSR (0 = CPSR)
|
||||
//d = rd
|
||||
void ARM::arm_op_move_to_register_from_status() {
|
||||
auto ARM::arm_op_move_to_register_from_status() {
|
||||
uint1 source = instruction() >> 22;
|
||||
uint4 d = instruction() >> 12;
|
||||
|
||||
|
@ -352,7 +293,7 @@ void ARM::arm_op_move_to_register_from_status() {
|
|||
//r = SPSR (0 = CPSR)
|
||||
//f = field mask
|
||||
//m = rm
|
||||
void ARM::arm_op_move_to_status_from_register() {
|
||||
auto ARM::arm_op_move_to_status_from_register() {
|
||||
uint4 m = instruction();
|
||||
|
||||
arm_move_to_status(r(m));
|
||||
|
@ -362,7 +303,7 @@ void ARM::arm_op_move_to_status_from_register() {
|
|||
//cccc 0001 0010 ++++ ++++ ++++ 0001 mmmm
|
||||
//c = condition
|
||||
//m = rm
|
||||
void ARM::arm_op_branch_exchange_register() {
|
||||
auto ARM::arm_op_branch_exchange_register() {
|
||||
uint4 m = instruction();
|
||||
|
||||
cpsr().t = r(m) & 1;
|
||||
|
@ -376,7 +317,7 @@ void ARM::arm_op_branch_exchange_register() {
|
|||
//f = field mask
|
||||
//r = rotate
|
||||
//i = immediate
|
||||
void ARM::arm_op_move_to_status_from_immediate() {
|
||||
auto ARM::arm_op_move_to_status_from_immediate() {
|
||||
uint4 rotate = instruction() >> 8;
|
||||
uint8 immediate = instruction();
|
||||
|
||||
|
@ -398,7 +339,7 @@ void ARM::arm_op_move_to_status_from_immediate() {
|
|||
//l = shift immediate
|
||||
//s = shift
|
||||
//m = rm
|
||||
void ARM::arm_op_data_immediate_shift() {
|
||||
auto ARM::arm_op_data_immediate_shift() {
|
||||
uint1 save = instruction() >> 20;
|
||||
uint5 shift = instruction() >> 7;
|
||||
uint2 mode = instruction() >> 5;
|
||||
|
@ -428,7 +369,7 @@ void ARM::arm_op_data_immediate_shift() {
|
|||
//s = rs
|
||||
//s = shift
|
||||
//m = rm
|
||||
void ARM::arm_op_data_register_shift() {
|
||||
auto ARM::arm_op_data_register_shift() {
|
||||
uint1 save = instruction() >> 20;
|
||||
uint4 s = instruction() >> 8;
|
||||
uint2 mode = instruction() >> 5;
|
||||
|
@ -457,7 +398,7 @@ void ARM::arm_op_data_register_shift() {
|
|||
//d = rd
|
||||
//s = shift immediate
|
||||
//i = immediate
|
||||
void ARM::arm_op_data_immediate() {
|
||||
auto ARM::arm_op_data_immediate() {
|
||||
uint1 save = instruction() >> 20;
|
||||
uint4 shift = instruction() >> 8;
|
||||
uint8 immediate = instruction();
|
||||
|
@ -482,7 +423,7 @@ void ARM::arm_op_data_immediate() {
|
|||
//n = rn
|
||||
//d = rd
|
||||
//i = immediate
|
||||
void ARM::arm_op_move_immediate_offset() {
|
||||
auto ARM::arm_op_move_immediate_offset() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 byte = instruction() >> 22;
|
||||
|
@ -517,7 +458,7 @@ void ARM::arm_op_move_immediate_offset() {
|
|||
//l = shift immediate
|
||||
//s = shift mode
|
||||
//m = rm
|
||||
void ARM::arm_op_move_register_offset() {
|
||||
auto ARM::arm_op_move_register_offset() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 byte = instruction() >> 22;
|
||||
|
@ -558,7 +499,7 @@ void ARM::arm_op_move_register_offset() {
|
|||
//l = load (0 = save)
|
||||
//n = rn
|
||||
//l = register list
|
||||
void ARM::arm_op_move_multiple() {
|
||||
auto ARM::arm_op_move_multiple() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 s = instruction() >> 22;
|
||||
|
@ -612,7 +553,7 @@ void ARM::arm_op_move_multiple() {
|
|||
//c = condition
|
||||
//l = link
|
||||
//d = displacement (24-bit signed)
|
||||
void ARM::arm_op_branch() {
|
||||
auto ARM::arm_op_branch() {
|
||||
uint1 link = instruction() >> 24;
|
||||
int24 displacement = instruction();
|
||||
|
||||
|
@ -624,7 +565,7 @@ void ARM::arm_op_branch() {
|
|||
//cccc 1111 iiii iiii iiii iiii iiii iiii
|
||||
//c = condition
|
||||
//i = immediate
|
||||
void ARM::arm_op_software_interrupt() {
|
||||
auto ARM::arm_op_software_interrupt() {
|
||||
uint24 immediate = instruction();
|
||||
|
||||
vector(0x00000008, Processor::Mode::SVC);
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
void arm_step();
|
||||
auto arm_opcode(uint32 rm);
|
||||
auto arm_move_to_status(uint32 rm);
|
||||
|
||||
void arm_opcode(uint32 rm);
|
||||
void arm_move_to_status(uint32 rm);
|
||||
auto arm_op_multiply();
|
||||
auto arm_op_multiply_long();
|
||||
auto arm_op_memory_swap();
|
||||
auto arm_op_move_half_register();
|
||||
auto arm_op_move_half_immediate();
|
||||
auto arm_op_load_register();
|
||||
auto arm_op_load_immediate();
|
||||
|
||||
void arm_op_multiply();
|
||||
void arm_op_multiply_long();
|
||||
void arm_op_memory_swap();
|
||||
void arm_op_move_half_register();
|
||||
void arm_op_move_half_immediate();
|
||||
void arm_op_load_register();
|
||||
void arm_op_load_immediate();
|
||||
auto arm_op_move_to_register_from_status();
|
||||
auto arm_op_move_to_status_from_register();
|
||||
auto arm_op_branch_exchange_register();
|
||||
|
||||
void arm_op_move_to_register_from_status();
|
||||
void arm_op_move_to_status_from_register();
|
||||
void arm_op_branch_exchange_register();
|
||||
|
||||
void arm_op_move_to_status_from_immediate();
|
||||
void arm_op_data_immediate_shift();
|
||||
void arm_op_data_register_shift();
|
||||
void arm_op_data_immediate();
|
||||
void arm_op_move_immediate_offset();
|
||||
void arm_op_move_register_offset();
|
||||
void arm_op_move_multiple();
|
||||
void arm_op_branch();
|
||||
void arm_op_software_interrupt();
|
||||
auto arm_op_move_to_status_from_immediate();
|
||||
auto arm_op_data_immediate_shift();
|
||||
auto arm_op_data_register_shift();
|
||||
auto arm_op_data_immediate();
|
||||
auto arm_op_move_immediate_offset();
|
||||
auto arm_op_move_register_offset();
|
||||
auto arm_op_move_multiple();
|
||||
auto arm_op_branch();
|
||||
auto arm_op_software_interrupt();
|
||||
|
|
|
@ -1,65 +1,6 @@
|
|||
#ifdef PROCESSOR_ARM_HPP
|
||||
|
||||
void ARM::thumb_step() {
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
r(15).data &= ~1;
|
||||
|
||||
sequential() = false;
|
||||
pipeline.fetch.address = r(15) & ~1;
|
||||
pipeline.fetch.instruction = read(pipeline.fetch.address, Half);
|
||||
|
||||
pipeline_step();
|
||||
}
|
||||
|
||||
pipeline_step();
|
||||
|
||||
if(processor.irqline && cpsr().i == 0) {
|
||||
vector(0x00000018, Processor::Mode::IRQ);
|
||||
r(14) += 2;
|
||||
return;
|
||||
}
|
||||
|
||||
instructions++;
|
||||
if(trace) {
|
||||
print(disassemble_registers(), "\n");
|
||||
print(disassemble_thumb_instruction(pipeline.execute.address), "\n");
|
||||
}
|
||||
|
||||
#define decode(pattern, execute) if( \
|
||||
(instruction() & std::integral_constant<uint32, bit::mask(pattern)>::value) \
|
||||
== std::integral_constant<uint32, bit::test(pattern)>::value \
|
||||
) return thumb_op_ ## execute()
|
||||
|
||||
decode("0001 10?? ???? ????", adjust_register);
|
||||
decode("0001 11?? ???? ????", adjust_immediate);
|
||||
decode("000? ???? ???? ????", shift_immediate);
|
||||
decode("001? ???? ???? ????", immediate);
|
||||
decode("0100 00?? ???? ????", alu);
|
||||
decode("0100 0111 0??? ?---", branch_exchange);
|
||||
decode("0100 01?? ???? ????", alu_hi);
|
||||
decode("0100 1??? ???? ????", load_literal);
|
||||
decode("0101 ???? ???? ????", move_register_offset);
|
||||
decode("0110 ???? ???? ????", move_word_immediate);
|
||||
decode("0111 ???? ???? ????", move_byte_immediate);
|
||||
decode("1000 ???? ???? ????", move_half_immediate);
|
||||
decode("1001 ???? ???? ????", move_stack);
|
||||
decode("1010 ???? ???? ????", add_register_hi);
|
||||
decode("1011 0000 ???? ????", adjust_stack);
|
||||
decode("1011 ?10? ???? ????", stack_multiple);
|
||||
decode("1100 ???? ???? ????", move_multiple);
|
||||
decode("1101 1111 ???? ????", software_interrupt);
|
||||
decode("1101 ???? ???? ????", branch_conditional);
|
||||
decode("1110 0??? ???? ????", branch_short);
|
||||
decode("1111 0??? ???? ????", branch_long_prefix);
|
||||
decode("1111 1??? ???? ????", branch_long_suffix);
|
||||
|
||||
#undef decode
|
||||
|
||||
crash = true;
|
||||
}
|
||||
|
||||
void ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) {
|
||||
auto ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) {
|
||||
switch(opcode) {
|
||||
case 0: r(d) = bit(r(d) & r(m)); break; //AND
|
||||
case 1: r(d) = bit(r(d) ^ r(m)); break; //EOR
|
||||
|
@ -74,7 +15,7 @@ void ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) {
|
|||
case 10: sub(r(d), r(m), 1); break; //CMP
|
||||
case 11: add(r(d), r(m), 0); break; //CMN
|
||||
case 12: r(d) = bit(r(d) | r(m)); break; //ORR
|
||||
case 13: r(d) = mul(0, r(d), r(m)); break; //MUL
|
||||
case 13: r(d) = mul(0, r(m), r(d)); break; //MUL
|
||||
case 14: r(d) = bit(r(d) & ~r(m)); break; //BIC
|
||||
case 15: r(d) = bit(~r(m)); break; //MVN
|
||||
}
|
||||
|
@ -86,7 +27,7 @@ void ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) {
|
|||
//m = rm
|
||||
//n = rn
|
||||
//d = rd
|
||||
void ARM::thumb_op_adjust_register() {
|
||||
auto ARM::thumb_op_adjust_register() {
|
||||
uint1 opcode = instruction() >> 9;
|
||||
uint3 m = instruction() >> 6;
|
||||
uint3 n = instruction() >> 3;
|
||||
|
@ -104,7 +45,7 @@ void ARM::thumb_op_adjust_register() {
|
|||
//i = immediate
|
||||
//n = rn
|
||||
//d = rd
|
||||
void ARM::thumb_op_adjust_immediate() {
|
||||
auto ARM::thumb_op_adjust_immediate() {
|
||||
uint1 opcode = instruction() >> 9;
|
||||
uint3 immediate = instruction() >> 6;
|
||||
uint3 n = instruction() >> 3;
|
||||
|
@ -122,7 +63,7 @@ void ARM::thumb_op_adjust_immediate() {
|
|||
//i = immediate
|
||||
//m = rm
|
||||
//d = rd
|
||||
void ARM::thumb_op_shift_immediate() {
|
||||
auto ARM::thumb_op_shift_immediate() {
|
||||
uint2 opcode = instruction() >> 11;
|
||||
uint5 immediate = instruction() >> 6;
|
||||
uint3 m = instruction() >> 3;
|
||||
|
@ -140,7 +81,7 @@ void ARM::thumb_op_shift_immediate() {
|
|||
//o = opcode
|
||||
//r = (rd,rn)
|
||||
//i = immediate
|
||||
void ARM::thumb_op_immediate() {
|
||||
auto ARM::thumb_op_immediate() {
|
||||
uint2 opcode = instruction() >> 11;
|
||||
uint3 d = instruction() >> 8;
|
||||
uint8 immediate = instruction();
|
||||
|
@ -158,7 +99,7 @@ void ARM::thumb_op_immediate() {
|
|||
//o = opcode
|
||||
//m = rm
|
||||
//d = rd
|
||||
void ARM::thumb_op_alu() {
|
||||
auto ARM::thumb_op_alu() {
|
||||
uint4 opcode = instruction() >> 6;
|
||||
uint3 m = instruction() >> 3;
|
||||
uint3 d = instruction();
|
||||
|
@ -169,7 +110,7 @@ void ARM::thumb_op_alu() {
|
|||
//bx rm
|
||||
//0100 0111 0mmm m---
|
||||
//m = rm
|
||||
void ARM::thumb_op_branch_exchange() {
|
||||
auto ARM::thumb_op_branch_exchange() {
|
||||
uint4 m = instruction() >> 3;
|
||||
|
||||
cpsr().t = r(m) & 1;
|
||||
|
@ -181,7 +122,7 @@ void ARM::thumb_op_branch_exchange() {
|
|||
//o = opcode
|
||||
//M:m = rm
|
||||
//D:d = rd
|
||||
void ARM::thumb_op_alu_hi() {
|
||||
auto ARM::thumb_op_alu_hi() {
|
||||
uint2 opcode = instruction() >> 8;
|
||||
uint4 m = instruction() >> 3;
|
||||
uint3 dl = instruction();
|
||||
|
@ -199,7 +140,7 @@ void ARM::thumb_op_alu_hi() {
|
|||
//0100 1ddd oooo oooo
|
||||
//d = rd
|
||||
//o = offset
|
||||
void ARM::thumb_op_load_literal() {
|
||||
auto ARM::thumb_op_load_literal() {
|
||||
uint3 d = instruction() >> 8;
|
||||
uint8 displacement = instruction();
|
||||
|
||||
|
@ -213,7 +154,7 @@ void ARM::thumb_op_load_literal() {
|
|||
//m = rm
|
||||
//n = rn
|
||||
//d = rd
|
||||
void ARM::thumb_op_move_register_offset() {
|
||||
auto ARM::thumb_op_move_register_offset() {
|
||||
uint3 opcode = instruction() >> 9;
|
||||
uint3 m = instruction() >> 6;
|
||||
uint3 n = instruction() >> 3;
|
||||
|
@ -237,7 +178,7 @@ void ARM::thumb_op_move_register_offset() {
|
|||
//o = offset
|
||||
//n = rn
|
||||
//d = rd
|
||||
void ARM::thumb_op_move_word_immediate() {
|
||||
auto ARM::thumb_op_move_word_immediate() {
|
||||
uint1 l = instruction() >> 11;
|
||||
uint5 offset = instruction() >> 6;
|
||||
uint3 n = instruction() >> 3;
|
||||
|
@ -253,7 +194,7 @@ void ARM::thumb_op_move_word_immediate() {
|
|||
//o = offset
|
||||
//n = rn
|
||||
//d = rd
|
||||
void ARM::thumb_op_move_byte_immediate() {
|
||||
auto ARM::thumb_op_move_byte_immediate() {
|
||||
uint1 l = instruction() >> 11;
|
||||
uint5 offset = instruction() >> 6;
|
||||
uint3 n = instruction() >> 3;
|
||||
|
@ -269,7 +210,7 @@ void ARM::thumb_op_move_byte_immediate() {
|
|||
//o = offset
|
||||
//n = rn
|
||||
//d = rd
|
||||
void ARM::thumb_op_move_half_immediate() {
|
||||
auto ARM::thumb_op_move_half_immediate() {
|
||||
uint1 l = instruction() >> 11;
|
||||
uint5 offset = instruction() >> 6;
|
||||
uint3 n = instruction() >> 3;
|
||||
|
@ -284,7 +225,7 @@ void ARM::thumb_op_move_half_immediate() {
|
|||
//l = load
|
||||
//d = rd
|
||||
//i = immediate
|
||||
void ARM::thumb_op_move_stack() {
|
||||
auto ARM::thumb_op_move_stack() {
|
||||
uint1 l = instruction() >> 11;
|
||||
uint3 d = instruction() >> 8;
|
||||
uint8 immediate = instruction();
|
||||
|
@ -298,7 +239,7 @@ void ARM::thumb_op_move_stack() {
|
|||
//s = sp (0 = pc)
|
||||
//d = rd
|
||||
//i = immediate
|
||||
void ARM::thumb_op_add_register_hi() {
|
||||
auto ARM::thumb_op_add_register_hi() {
|
||||
uint1 sp = instruction() >> 11;
|
||||
uint3 d = instruction() >> 8;
|
||||
uint8 immediate = instruction();
|
||||
|
@ -311,7 +252,7 @@ void ARM::thumb_op_add_register_hi() {
|
|||
//1011 0000 oiii iiii
|
||||
//o = opcode
|
||||
//i = immediate
|
||||
void ARM::thumb_op_adjust_stack() {
|
||||
auto ARM::thumb_op_adjust_stack() {
|
||||
uint1 opcode = instruction() >> 7;
|
||||
uint7 immediate = instruction();
|
||||
|
||||
|
@ -325,7 +266,7 @@ void ARM::thumb_op_adjust_stack() {
|
|||
//o = opcode (0 = push, 1 = pop)
|
||||
//r = push lr -or- pop pc
|
||||
//l = register list
|
||||
void ARM::thumb_op_stack_multiple() {
|
||||
auto ARM::thumb_op_stack_multiple() {
|
||||
uint1 l = instruction() >> 11;
|
||||
uint1 branch = instruction() >> 8;
|
||||
uint8 list = instruction();
|
||||
|
@ -336,7 +277,7 @@ void ARM::thumb_op_stack_multiple() {
|
|||
|
||||
sequential() = false;
|
||||
for(unsigned m = 0; m < 8; m++) {
|
||||
if(list & (1 << m)) {
|
||||
if(list & 1 << m) {
|
||||
if(l == 1) r(m) = read(sp, Word); //POP
|
||||
if(l == 0) write(sp, Word, r(m)); //PUSH
|
||||
sp += 4;
|
||||
|
@ -360,27 +301,29 @@ void ARM::thumb_op_stack_multiple() {
|
|||
//l = load (0 = save)
|
||||
//n = rn
|
||||
//l = register list
|
||||
void ARM::thumb_op_move_multiple() {
|
||||
auto ARM::thumb_op_move_multiple() {
|
||||
uint1 l = instruction() >> 11;
|
||||
uint3 n = instruction() >> 8;
|
||||
uint8 list = instruction();
|
||||
uint32 rn = r(n); //rn may be in register list; so we must cache it
|
||||
|
||||
sequential() = false;
|
||||
for(unsigned m = 0; m < 8; m++) {
|
||||
if(list & (1 << m)) {
|
||||
if(l == 1) r(m) = read(r(n), Word); //LDMIA
|
||||
if(l == 0) write(r(n), Word, r(m)); //STMIA
|
||||
r(n) += 4;
|
||||
if(list & 1 << m) {
|
||||
if(l == 1) r(m) = read(rn, Word); //LDMIA
|
||||
if(l == 0) write(rn, Word, r(m)); //STMIA
|
||||
rn += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if(l == 0 || (list & 1 << n) == 0) r(n) = rn; //update rn on save or when not in register list
|
||||
if(l == 1) idle();
|
||||
}
|
||||
|
||||
//swi #immediate
|
||||
//1101 1111 iiii iiii
|
||||
//i = immediate
|
||||
void ARM::thumb_op_software_interrupt() {
|
||||
auto ARM::thumb_op_software_interrupt() {
|
||||
uint8 immediate = instruction();
|
||||
|
||||
vector(0x00000008, Processor::Mode::SVC);
|
||||
|
@ -390,7 +333,7 @@ void ARM::thumb_op_software_interrupt() {
|
|||
//1101 cccc dddd dddd
|
||||
//c = condition
|
||||
//d = displacement
|
||||
void ARM::thumb_op_branch_conditional() {
|
||||
auto ARM::thumb_op_branch_conditional() {
|
||||
uint4 flagcondition = instruction() >> 8;
|
||||
int8 displacement = instruction();
|
||||
|
||||
|
@ -401,7 +344,7 @@ void ARM::thumb_op_branch_conditional() {
|
|||
//b address
|
||||
//1110 0ooo oooo oooo
|
||||
//o = offset
|
||||
void ARM::thumb_op_branch_short() {
|
||||
auto ARM::thumb_op_branch_short() {
|
||||
int11 displacement = instruction();
|
||||
|
||||
r(15) += displacement * 2;
|
||||
|
@ -410,7 +353,7 @@ void ARM::thumb_op_branch_short() {
|
|||
//bl address
|
||||
//1111 0ooo oooo oooo
|
||||
//o = offset
|
||||
void ARM::thumb_op_branch_long_prefix() {
|
||||
auto ARM::thumb_op_branch_long_prefix() {
|
||||
int11 offsethi = instruction();
|
||||
|
||||
r(14) = r(15) + ((offsethi * 2) << 11);
|
||||
|
@ -419,7 +362,7 @@ void ARM::thumb_op_branch_long_prefix() {
|
|||
//bl address
|
||||
//1111 1ooo oooo oooo
|
||||
//o = offset
|
||||
void ARM::thumb_op_branch_long_suffix() {
|
||||
auto ARM::thumb_op_branch_long_suffix() {
|
||||
uint11 offsetlo = instruction();
|
||||
|
||||
r(15) = r(14) + (offsetlo * 2);
|
||||
|
|
|
@ -1,26 +1,24 @@
|
|||
void thumb_step();
|
||||
auto thumb_opcode(uint4 opcode, uint4 d, uint4 s);
|
||||
|
||||
void thumb_opcode(uint4 opcode, uint4 d, uint4 s);
|
||||
|
||||
void thumb_op_adjust_register();
|
||||
void thumb_op_adjust_immediate();
|
||||
void thumb_op_shift_immediate();
|
||||
void thumb_op_immediate();
|
||||
void thumb_op_alu();
|
||||
void thumb_op_branch_exchange();
|
||||
void thumb_op_alu_hi();
|
||||
void thumb_op_load_literal();
|
||||
void thumb_op_move_register_offset();
|
||||
void thumb_op_move_word_immediate();
|
||||
void thumb_op_move_byte_immediate();
|
||||
void thumb_op_move_half_immediate();
|
||||
void thumb_op_move_stack();
|
||||
void thumb_op_add_register_hi();
|
||||
void thumb_op_adjust_stack();
|
||||
void thumb_op_stack_multiple();
|
||||
void thumb_op_move_multiple();
|
||||
void thumb_op_software_interrupt();
|
||||
void thumb_op_branch_conditional();
|
||||
void thumb_op_branch_short();
|
||||
void thumb_op_branch_long_prefix();
|
||||
void thumb_op_branch_long_suffix();
|
||||
auto thumb_op_adjust_register();
|
||||
auto thumb_op_adjust_immediate();
|
||||
auto thumb_op_shift_immediate();
|
||||
auto thumb_op_immediate();
|
||||
auto thumb_op_alu();
|
||||
auto thumb_op_branch_exchange();
|
||||
auto thumb_op_alu_hi();
|
||||
auto thumb_op_load_literal();
|
||||
auto thumb_op_move_register_offset();
|
||||
auto thumb_op_move_word_immediate();
|
||||
auto thumb_op_move_byte_immediate();
|
||||
auto thumb_op_move_half_immediate();
|
||||
auto thumb_op_move_stack();
|
||||
auto thumb_op_add_register_hi();
|
||||
auto thumb_op_adjust_stack();
|
||||
auto thumb_op_stack_multiple();
|
||||
auto thumb_op_move_multiple();
|
||||
auto thumb_op_software_interrupt();
|
||||
auto thumb_op_branch_conditional();
|
||||
auto thumb_op_branch_short();
|
||||
auto thumb_op_branch_long_prefix();
|
||||
auto thumb_op_branch_long_suffix();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifdef PROCESSOR_ARM_HPP
|
||||
|
||||
void ARM::Processor::power() {
|
||||
auto ARM::Processor::power() -> void {
|
||||
r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = 0;
|
||||
usr.r8 = usr.r9 = usr.r10 = usr.r11 = usr.r12 = usr.sp = usr.lr = 0;
|
||||
fiq.r8 = fiq.r9 = fiq.r10 = fiq.r11 = fiq.r12 = fiq.sp = fiq.lr = 0;
|
||||
|
@ -34,7 +34,7 @@ void ARM::Processor::power() {
|
|||
r[15] = &pc;
|
||||
}
|
||||
|
||||
void ARM::Processor::setMode(Mode mode) {
|
||||
auto ARM::Processor::setMode(Mode mode) -> void {
|
||||
cpsr.m = 0x10 | (unsigned)mode;
|
||||
|
||||
if(mode == Mode::FIQ) {
|
||||
|
@ -61,7 +61,7 @@ void ARM::Processor::setMode(Mode mode) {
|
|||
}
|
||||
}
|
||||
|
||||
void ARM::pipeline_step() {
|
||||
auto ARM::pipeline_step() -> void {
|
||||
pipeline.execute = pipeline.decode;
|
||||
pipeline.decode = pipeline.fetch;
|
||||
|
||||
|
|
|
@ -1,39 +1,30 @@
|
|||
struct GPR {
|
||||
uint32 data;
|
||||
function<void ()> modify;
|
||||
|
||||
inline operator uint32() const { return data; }
|
||||
inline GPR& operator=(uint32 n) { data = n; if(modify) modify(); return *this; }
|
||||
inline GPR& operator=(const GPR& source) { return operator=(source.data); }
|
||||
inline auto operator=(uint32 n) { data = n; if(modify) modify(); return *this; }
|
||||
inline auto operator=(const GPR& source) { return operator=(source.data); }
|
||||
|
||||
inline GPR& operator &=(uint32 n) { return operator=(data & n); }
|
||||
inline GPR& operator |=(uint32 n) { return operator=(data | n); }
|
||||
inline GPR& operator ^=(uint32 n) { return operator=(data ^ n); }
|
||||
inline GPR& operator +=(uint32 n) { return operator=(data + n); }
|
||||
inline GPR& operator -=(uint32 n) { return operator=(data - n); }
|
||||
inline GPR& operator *=(uint32 n) { return operator=(data * n); }
|
||||
inline GPR& operator /=(uint32 n) { return operator=(data / n); }
|
||||
inline GPR& operator %=(uint32 n) { return operator=(data % n); }
|
||||
inline GPR& operator<<=(uint32 n) { return operator=(data << n); }
|
||||
inline GPR& operator>>=(uint32 n) { return operator=(data >> n); }
|
||||
inline auto operator &=(uint32 n) { return operator=(data & n); }
|
||||
inline auto operator |=(uint32 n) { return operator=(data | n); }
|
||||
inline auto operator ^=(uint32 n) { return operator=(data ^ n); }
|
||||
inline auto operator +=(uint32 n) { return operator=(data + n); }
|
||||
inline auto operator -=(uint32 n) { return operator=(data - n); }
|
||||
inline auto operator *=(uint32 n) { return operator=(data * n); }
|
||||
inline auto operator /=(uint32 n) { return operator=(data / n); }
|
||||
inline auto operator %=(uint32 n) { return operator=(data % n); }
|
||||
inline auto operator<<=(uint32 n) { return operator=(data << n); }
|
||||
inline auto operator>>=(uint32 n) { return operator=(data >> n); }
|
||||
|
||||
uint32 data{0};
|
||||
function<void ()> modify;
|
||||
};
|
||||
|
||||
struct PSR {
|
||||
bool n; //negative
|
||||
bool z; //zero
|
||||
bool c; //carry
|
||||
bool v; //overflow
|
||||
bool i; //irq
|
||||
bool f; //fiq
|
||||
bool t; //thumb
|
||||
unsigned m; //mode
|
||||
|
||||
inline operator uint32() const {
|
||||
return (n << 31) + (z << 30) + (c << 29) + (v << 28)
|
||||
+ (i << 7) + (f << 6) + (t << 5) + (m << 0);
|
||||
}
|
||||
|
||||
inline PSR& operator=(uint32 d) {
|
||||
inline auto operator=(uint32 d) {
|
||||
n = d & (1 << 31);
|
||||
z = d & (1 << 30);
|
||||
c = d & (1 << 29);
|
||||
|
@ -45,15 +36,24 @@ struct PSR {
|
|||
return *this;
|
||||
}
|
||||
|
||||
void serialize(serializer&);
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
bool n{false}; //negative
|
||||
bool z{false}; //zero
|
||||
bool c{false}; //carry
|
||||
bool v{false}; //overflow
|
||||
bool i{false}; //irq
|
||||
bool f{false}; //fiq
|
||||
bool t{false}; //thumb
|
||||
unsigned m{0}; //mode
|
||||
};
|
||||
|
||||
struct Pipeline {
|
||||
bool reload;
|
||||
bool reload{false};
|
||||
|
||||
struct Instruction {
|
||||
uint32 address;
|
||||
uint32 instruction;
|
||||
uint32 address{0};
|
||||
uint32 instruction{0};
|
||||
};
|
||||
|
||||
Instruction execute;
|
||||
|
@ -105,29 +105,29 @@ struct Processor {
|
|||
|
||||
GPR pc;
|
||||
PSR cpsr;
|
||||
bool carryout;
|
||||
bool sequential;
|
||||
bool irqline;
|
||||
bool carryout{false};
|
||||
bool sequential{false};
|
||||
bool irqline{false};
|
||||
|
||||
GPR* r[16];
|
||||
PSR* spsr;
|
||||
|
||||
void power();
|
||||
void setMode(Mode);
|
||||
auto power() -> void;
|
||||
auto setMode(Mode) -> void;
|
||||
};
|
||||
|
||||
Processor processor;
|
||||
Pipeline pipeline;
|
||||
bool crash;
|
||||
bool crash{false};
|
||||
|
||||
void pipeline_step();
|
||||
auto pipeline_step() -> void;
|
||||
|
||||
alwaysinline GPR& r(unsigned n) { return *processor.r[n]; }
|
||||
alwaysinline PSR& cpsr() { return processor.cpsr; }
|
||||
alwaysinline PSR& spsr() { return *processor.spsr; }
|
||||
alwaysinline bool& carryout() { return processor.carryout; }
|
||||
alwaysinline bool& sequential() { return processor.sequential; }
|
||||
alwaysinline uint32 instruction() { return pipeline.execute.instruction; }
|
||||
alwaysinline Processor::Mode mode() { return (Processor::Mode)processor.cpsr.m; }
|
||||
alwaysinline bool privilegedmode() const { return (Processor::Mode)processor.cpsr.m != Processor::Mode::USR; }
|
||||
alwaysinline bool exceptionmode() const { return privilegedmode() && (Processor::Mode)processor.cpsr.m != Processor::Mode::SYS; }
|
||||
alwaysinline auto r(unsigned n) -> GPR& { return *processor.r[n]; }
|
||||
alwaysinline auto cpsr() -> PSR& { return processor.cpsr; }
|
||||
alwaysinline auto spsr() -> PSR& { return *processor.spsr; }
|
||||
alwaysinline auto carryout() -> bool& { return processor.carryout; }
|
||||
alwaysinline auto sequential() -> bool& { return processor.sequential; }
|
||||
alwaysinline auto instruction() -> uint32 { return pipeline.execute.instruction; }
|
||||
alwaysinline auto mode() -> Processor::Mode { return (Processor::Mode)processor.cpsr.m; }
|
||||
alwaysinline auto privilegedmode() const -> bool { return (Processor::Mode)processor.cpsr.m != Processor::Mode::USR; }
|
||||
alwaysinline auto exceptionmode() const -> bool { return privilegedmode() && (Processor::Mode)processor.cpsr.m != Processor::Mode::SYS; }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
void ARM::PSR::serialize(serializer& s) {
|
||||
auto ARM::PSR::serialize(serializer& s) -> void {
|
||||
s.integer(n);
|
||||
s.integer(z);
|
||||
s.integer(c);
|
||||
|
@ -9,7 +9,7 @@ void ARM::PSR::serialize(serializer& s) {
|
|||
s.integer(m);
|
||||
}
|
||||
|
||||
void ARM::serialize(serializer& s) {
|
||||
auto ARM::serialize(serializer& s) -> void {
|
||||
s.integer(processor.r0.data);
|
||||
s.integer(processor.r1.data);
|
||||
s.integer(processor.r2.data);
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
auto ARM::arm_step() -> void {
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
r(15).data &= ~3;
|
||||
|
||||
sequential() = false;
|
||||
pipeline.fetch.address = r(15) & ~3;
|
||||
pipeline.fetch.instruction = read(pipeline.fetch.address, Word);
|
||||
|
||||
pipeline_step();
|
||||
}
|
||||
|
||||
pipeline_step();
|
||||
|
||||
if(processor.irqline && cpsr().i == 0) {
|
||||
vector(0x00000018, Processor::Mode::IRQ);
|
||||
return;
|
||||
}
|
||||
|
||||
instructions++;
|
||||
if(trace) {
|
||||
print(disassemble_registers(), "\n");
|
||||
print(disassemble_arm_instruction(pipeline.execute.address), "\n");
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
if(condition(instruction() >> 28) == false) return;
|
||||
|
||||
#define decode(pattern, execute) if( \
|
||||
(instruction() & std::integral_constant<uint32, bit::mask(pattern)>::value) \
|
||||
== std::integral_constant<uint32, bit::test(pattern)>::value \
|
||||
) return arm_op_ ## execute()
|
||||
|
||||
decode("???? 0001 0010 ++++ ++++ ++++ 0001 ????", branch_exchange_register);
|
||||
decode("???? 0000 00?? ???? ???? ???? 1001 ????", multiply);
|
||||
decode("???? 0000 1??? ???? ???? ???? 1001 ????", multiply_long);
|
||||
decode("???? 0001 0?00 ++++ ???? ---- 0000 ----", move_to_register_from_status);
|
||||
decode("???? 0001 0?00 ???? ???? ---- 1001 ????", memory_swap);
|
||||
decode("???? 0001 0?10 ???? ++++ ---- 0000 ????", move_to_status_from_register);
|
||||
decode("???? 0011 0?10 ???? ++++ ???? ???? ????", move_to_status_from_immediate);
|
||||
decode("???? 000? ?0?1 ???? ???? ---- 11?1 ????", load_register);
|
||||
decode("???? 000? ?1?1 ???? ???? ???? 11?1 ????", load_immediate);
|
||||
decode("???? 000? ?0?? ???? ???? ---- 1011 ????", move_half_register);
|
||||
decode("???? 000? ?1?? ???? ???? ???? 1011 ????", move_half_immediate);
|
||||
decode("???? 000? ???? ???? ???? ???? ???0 ????", data_immediate_shift);
|
||||
decode("???? 000? ???? ???? ???? ???? 0??1 ????", data_register_shift);
|
||||
decode("???? 001? ???? ???? ???? ???? ???? ????", data_immediate);
|
||||
decode("???? 010? ???? ???? ???? ???? ???? ????", move_immediate_offset);
|
||||
decode("???? 011? ???? ???? ???? ???? ???0 ????", move_register_offset);
|
||||
decode("???? 100? ???? ???? ???? ???? ???? ????", move_multiple);
|
||||
decode("???? 101? ???? ???? ???? ???? ???? ????", branch);
|
||||
decode("???? 1111 ???? ???? ???? ???? ???? ????", software_interrupt);
|
||||
|
||||
#undef decode
|
||||
|
||||
crash = true;
|
||||
}
|
||||
|
||||
auto ARM::thumb_step() -> void {
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
r(15).data &= ~1;
|
||||
|
||||
sequential() = false;
|
||||
pipeline.fetch.address = r(15) & ~1;
|
||||
pipeline.fetch.instruction = read(pipeline.fetch.address, Half);
|
||||
|
||||
pipeline_step();
|
||||
}
|
||||
|
||||
pipeline_step();
|
||||
|
||||
if(processor.irqline && cpsr().i == 0) {
|
||||
vector(0x00000018, Processor::Mode::IRQ);
|
||||
r(14) += 2;
|
||||
return;
|
||||
}
|
||||
|
||||
instructions++;
|
||||
if(trace) {
|
||||
print(disassemble_registers(), "\n");
|
||||
print(disassemble_thumb_instruction(pipeline.execute.address), "\n");
|
||||
}
|
||||
|
||||
#define decode(pattern, execute) if( \
|
||||
(instruction() & std::integral_constant<uint32, bit::mask(pattern)>::value) \
|
||||
== std::integral_constant<uint32, bit::test(pattern)>::value \
|
||||
) return thumb_op_ ## execute()
|
||||
|
||||
decode("0001 10?? ???? ????", adjust_register);
|
||||
decode("0001 11?? ???? ????", adjust_immediate);
|
||||
decode("000? ???? ???? ????", shift_immediate);
|
||||
decode("001? ???? ???? ????", immediate);
|
||||
decode("0100 00?? ???? ????", alu);
|
||||
decode("0100 0111 0??? ?---", branch_exchange);
|
||||
decode("0100 01?? ???? ????", alu_hi);
|
||||
decode("0100 1??? ???? ????", load_literal);
|
||||
decode("0101 ???? ???? ????", move_register_offset);
|
||||
decode("0110 ???? ???? ????", move_word_immediate);
|
||||
decode("0111 ???? ???? ????", move_byte_immediate);
|
||||
decode("1000 ???? ???? ????", move_half_immediate);
|
||||
decode("1001 ???? ???? ????", move_stack);
|
||||
decode("1010 ???? ???? ????", add_register_hi);
|
||||
decode("1011 0000 ???? ????", adjust_stack);
|
||||
decode("1011 ?10? ???? ????", stack_multiple);
|
||||
decode("1100 ???? ???? ????", move_multiple);
|
||||
decode("1101 1111 ???? ????", software_interrupt);
|
||||
decode("1101 ???? ???? ????", branch_conditional);
|
||||
decode("1110 0??? ???? ????", branch_short);
|
||||
decode("1111 0??? ???? ????", branch_long_prefix);
|
||||
decode("1111 1??? ???? ????", branch_long_suffix);
|
||||
|
||||
#undef decode
|
||||
|
||||
crash = true;
|
||||
}
|
Loading…
Reference in New Issue