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 {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
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 Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
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) {
|
uint32 CPU::bus_read(uint32 addr, uint32 size) {
|
||||||
step(bus.speed(addr, size));
|
step(bus.wait(addr, size));
|
||||||
return bus.read(addr, size);
|
return bus.read(addr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::bus_write(uint32 addr, uint32 size, uint32 word) {
|
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);
|
return bus.write(addr, size, word);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,10 +16,10 @@ void CPU::dma_transfer(Registers::DMA& dma) {
|
||||||
|
|
||||||
sequential() = false;
|
sequential() = false;
|
||||||
do {
|
do {
|
||||||
step(bus.speed(dma.run.source, size));
|
step(bus.wait(dma.run.source, size));
|
||||||
uint32 word = bus.read(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);
|
bus.write(dma.run.target, size, word);
|
||||||
|
|
||||||
sequential() = true;
|
sequential() = true;
|
||||||
|
|
|
@ -150,7 +150,7 @@ struct Registers {
|
||||||
|
|
||||||
struct WaitControl {
|
struct WaitControl {
|
||||||
uint2 nwait[4];
|
uint2 nwait[4];
|
||||||
uint2 swait[4];
|
uint1 swait[4];
|
||||||
uint2 phi;
|
uint2 phi;
|
||||||
uint1 prefetch;
|
uint1 prefetch;
|
||||||
uint1 gametype;
|
uint1 gametype;
|
||||||
|
|
|
@ -7,13 +7,13 @@ namespace GameBoyAdvance {
|
||||||
Bus bus;
|
Bus bus;
|
||||||
|
|
||||||
struct UnmappedMemory : Memory {
|
struct UnmappedMemory : Memory {
|
||||||
uint32 read(uint32 addr, uint32 size) { return 0u; }
|
auto read(uint32 addr, uint32 size) -> uint32 { return 0; }
|
||||||
void write(uint32 addr, uint32 size, uint32 word) {}
|
auto write(uint32 addr, uint32 size, uint32 word) -> void {}
|
||||||
};
|
};
|
||||||
|
|
||||||
static UnmappedMemory unmappedMemory;
|
static UnmappedMemory unmappedMemory;
|
||||||
|
|
||||||
uint32 Bus::mirror(uint32 addr, uint32 size) {
|
auto Bus::mirror(uint32 addr, uint32 size) -> uint32 {
|
||||||
uint32 base = 0;
|
uint32 base = 0;
|
||||||
if(size) {
|
if(size) {
|
||||||
uint32 mask = 1 << 27; //28-bit bus
|
uint32 mask = 1 << 27; //28-bit bus
|
||||||
|
@ -31,46 +31,46 @@ uint32 Bus::mirror(uint32 addr, uint32 size) {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Bus::speed(uint32 addr, uint32 size) {
|
auto Bus::wait(uint32 addr, uint32 size) -> unsigned {
|
||||||
if(addr & 0x08000000) {
|
switch(addr & 0x0f000000) {
|
||||||
static unsigned timing[] = {5, 4, 3, 9};
|
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 n = cpu.regs.wait.control.nwait[addr >> 25 & 3];
|
||||||
unsigned s = cpu.regs.wait.control.swait[addr >> 25 & 3];
|
unsigned s = cpu.regs.wait.control.swait[addr >> 25 & 3];
|
||||||
|
|
||||||
|
static unsigned timing[] = {5, 4, 3, 9};
|
||||||
n = timing[n];
|
n = timing[n];
|
||||||
|
|
||||||
switch(addr >> 25 & 3) {
|
switch(addr & 0x0e000000) {
|
||||||
case 0: s = s ? 3 : 2; break;
|
case 0x08000000: s = s ? 2 : 3; break;
|
||||||
case 1: s = s ? 5 : 2; break;
|
case 0x0a000000: s = s ? 2 : 5; break;
|
||||||
case 2: s = s ? 9 : 2; break;
|
case 0x0c000000: s = s ? 2 : 9; break;
|
||||||
case 3: s = n; break;
|
case 0x0e000000: s = n; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sequential = cpu.sequential();
|
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(idleflag) sequential = false; //LDR/LDM interrupts instruction fetches
|
||||||
|
|
||||||
if(sequential) return s << (size == Word); //16-bit bus requires two transfers for words
|
unsigned clocks = sequential ? s : n;
|
||||||
if(size == Word) n += s;
|
if(size == Word) clocks += s; //16-bit bus requires two transfers for words
|
||||||
return n;
|
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;
|
if(addr & 0x08000000) idleflag = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Bus::read(uint32 addr, uint32 size) {
|
auto Bus::read(uint32 addr, uint32 size) -> uint32 {
|
||||||
idleflag = false;
|
idleflag = false;
|
||||||
if(addr & 0x08000000) return cartridge.read(addr, size);
|
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;
|
idleflag = false;
|
||||||
if(addr & 0x08000000) return cartridge.write(addr, size, word);
|
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;
|
for(unsigned n = 0; n < 0x400; n++) mmio[n] = &unmappedMemory;
|
||||||
idleflag = false;
|
idleflag = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,28 @@
|
||||||
struct Memory {
|
struct Memory {
|
||||||
virtual uint32 read(uint32 addr, uint32 size) = 0;
|
virtual auto read(uint32 addr, uint32 size) -> uint32 = 0;
|
||||||
virtual void write(uint32 addr, uint32 size, uint32 word) = 0;
|
virtual auto write(uint32 addr, uint32 size, uint32 word) -> void = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MMIO : Memory {
|
struct MMIO : Memory {
|
||||||
virtual uint8 read(uint32 addr) = 0;
|
virtual auto read(uint32 addr) -> uint8 = 0;
|
||||||
virtual void write(uint32 addr, uint8 data) = 0;
|
virtual auto write(uint32 addr, uint8 data) -> void = 0;
|
||||||
uint32 read(uint32 addr, uint32 size);
|
auto read(uint32 addr, uint32 size) -> uint32;
|
||||||
void write(uint32 addr, uint32 size, uint32 word);
|
auto write(uint32 addr, uint32 size, uint32 word) -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Bus : Memory {
|
struct Bus : Memory {
|
||||||
Memory* mmio[0x400];
|
static auto mirror(uint32 addr, uint32 size) -> uint32;
|
||||||
bool idleflag;
|
|
||||||
static uint32 mirror(uint32 addr, uint32 size);
|
|
||||||
|
|
||||||
uint32 speed(uint32 addr, uint32 size);
|
auto wait(uint32 addr, uint32 size) -> unsigned;
|
||||||
void idle(uint32 addr);
|
auto idle(uint32 addr) -> void;
|
||||||
uint32 read(uint32 addr, uint32 size);
|
auto read(uint32 addr, uint32 size) -> uint32;
|
||||||
void write(uint32 addr, uint32 size, uint32 word);
|
auto write(uint32 addr, uint32 size, uint32 word) -> void;
|
||||||
void power();
|
auto power() -> void;
|
||||||
|
|
||||||
void serialize(serializer&);
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
|
Memory* mmio[0x400]{nullptr};
|
||||||
|
bool idleflag{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Bus bus;
|
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;
|
uint32 word = 0;
|
||||||
|
|
||||||
switch(size) {
|
switch(size) {
|
||||||
|
@ -22,7 +22,7 @@ uint32 MMIO::read(uint32 addr, uint32 size) {
|
||||||
return word;
|
return word;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MMIO::write(uint32 addr, uint32 size, uint32 word) {
|
auto MMIO::write(uint32 addr, uint32 size, uint32 word) -> void {
|
||||||
switch(size) {
|
switch(size) {
|
||||||
case Word:
|
case Word:
|
||||||
addr &= ~3;
|
addr &= ~3;
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
void Bus::serialize(serializer& s) {
|
auto Bus::serialize(serializer& s) -> void {
|
||||||
s.integer(idleflag);
|
s.integer(idleflag);
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace nall {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define PLATFORM_WINDOWS
|
#define PLATFORM_WINDOWS
|
||||||
#define API_WINDOWS
|
#define API_WINDOWS
|
||||||
#define DISPLAY_WINDOW
|
#define DISPLAY_WINDOWS
|
||||||
auto Intrinsics::platform() -> Platform { return Platform::Windows; }
|
auto Intrinsics::platform() -> Platform { return Platform::Windows; }
|
||||||
auto Intrinsics::api() -> API { return API::Windows; }
|
auto Intrinsics::api() -> API { return API::Windows; }
|
||||||
auto Intrinsics::display() -> Display { return Display::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) {
|
switch(condition) {
|
||||||
case 0: return cpsr().z == 1; //EQ (equal)
|
case 0: return cpsr().z == 1; //EQ (equal)
|
||||||
case 1: return cpsr().z == 0; //NE (not 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)) {
|
if(cpsr().t || instruction() & (1 << 20)) {
|
||||||
cpsr().n = result >> 31;
|
cpsr().n = result >> 31;
|
||||||
cpsr().z = result == 0;
|
cpsr().z = result == 0;
|
||||||
|
@ -28,7 +28,7 @@ uint32 ARM::bit(uint32 result) {
|
||||||
return 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;
|
uint32 result = source + modify + carry;
|
||||||
if(cpsr().t || instruction() & (1 << 20)) {
|
if(cpsr().t || instruction() & (1 << 20)) {
|
||||||
uint32 overflow = ~(source ^ modify) & (source ^ result);
|
uint32 overflow = ~(source ^ modify) & (source ^ result);
|
||||||
|
@ -40,11 +40,16 @@ uint32 ARM::add(uint32 source, uint32 modify, bool carry) {
|
||||||
return result;
|
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);
|
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;
|
product += multiplicand * multiplier;
|
||||||
|
|
||||||
if(cpsr().t || instruction() & (1 << 20)) {
|
if(cpsr().t || instruction() & (1 << 20)) {
|
||||||
|
@ -55,7 +60,7 @@ uint32 ARM::mul(uint32 product, uint32 multiplicand, uint32 multiplier) {
|
||||||
return product;
|
return product;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ARM::lsl(uint32 source, uint8 shift) {
|
auto ARM::lsl(uint32 source, uint8 shift) -> uint32 {
|
||||||
carryout() = cpsr().c;
|
carryout() = cpsr().c;
|
||||||
if(shift == 0) return source;
|
if(shift == 0) return source;
|
||||||
|
|
||||||
|
@ -64,7 +69,7 @@ uint32 ARM::lsl(uint32 source, uint8 shift) {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ARM::lsr(uint32 source, uint8 shift) {
|
auto ARM::lsr(uint32 source, uint8 shift) -> uint32 {
|
||||||
carryout() = cpsr().c;
|
carryout() = cpsr().c;
|
||||||
if(shift == 0) return source;
|
if(shift == 0) return source;
|
||||||
|
|
||||||
|
@ -73,7 +78,7 @@ uint32 ARM::lsr(uint32 source, uint8 shift) {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ARM::asr(uint32 source, uint8 shift) {
|
auto ARM::asr(uint32 source, uint8 shift) -> uint32 {
|
||||||
carryout() = cpsr().c;
|
carryout() = cpsr().c;
|
||||||
if(shift == 0) return source;
|
if(shift == 0) return source;
|
||||||
|
|
||||||
|
@ -82,7 +87,7 @@ uint32 ARM::asr(uint32 source, uint8 shift) {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ARM::ror(uint32 source, uint8 shift) {
|
auto ARM::ror(uint32 source, uint8 shift) -> uint32 {
|
||||||
carryout() = cpsr().c;
|
carryout() = cpsr().c;
|
||||||
if(shift == 0) return source;
|
if(shift == 0) return source;
|
||||||
|
|
||||||
|
@ -92,7 +97,7 @@ uint32 ARM::ror(uint32 source, uint8 shift) {
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ARM::rrx(uint32 source) {
|
auto ARM::rrx(uint32 source) -> uint32 {
|
||||||
carryout() = source & 1;
|
carryout() = source & 1;
|
||||||
return (cpsr().c << 31) | (source >> 1);
|
return (cpsr().c << 31) | (source >> 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,11 @@ namespace Processor {
|
||||||
#include "algorithms.cpp"
|
#include "algorithms.cpp"
|
||||||
#include "instructions-arm.cpp"
|
#include "instructions-arm.cpp"
|
||||||
#include "instructions-thumb.cpp"
|
#include "instructions-thumb.cpp"
|
||||||
|
#include "step.cpp"
|
||||||
#include "disassembler.cpp"
|
#include "disassembler.cpp"
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
|
|
||||||
void ARM::power() {
|
auto ARM::power() -> void {
|
||||||
processor.power();
|
processor.power();
|
||||||
vector(0x00000000, Processor::Mode::SVC);
|
vector(0x00000000, Processor::Mode::SVC);
|
||||||
pipeline.reload = true;
|
pipeline.reload = true;
|
||||||
|
@ -23,21 +24,21 @@ void ARM::power() {
|
||||||
instructions = 0;
|
instructions = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM::exec() {
|
auto ARM::exec() -> void {
|
||||||
cpsr().t ? thumb_step() : arm_step();
|
cpsr().t ? thumb_step() : arm_step();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM::idle() {
|
auto ARM::idle() -> void {
|
||||||
bus_idle(r(15));
|
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);
|
uint32 word = bus_read(addr, size);
|
||||||
sequential() = true;
|
sequential() = true;
|
||||||
return word;
|
return word;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ARM::load(uint32 addr, uint32 size) {
|
auto ARM::load(uint32 addr, uint32 size) -> uint32 {
|
||||||
sequential() = false;
|
sequential() = false;
|
||||||
uint32 word = read(addr, size);
|
uint32 word = read(addr, size);
|
||||||
|
|
||||||
|
@ -52,12 +53,12 @@ uint32 ARM::load(uint32 addr, uint32 size) {
|
||||||
return word;
|
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);
|
bus_write(addr, size, word);
|
||||||
sequential() = true;
|
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 == Half) { word &= 0xffff; word |= word << 16; }
|
||||||
if(size == Byte) { word &= 0xff; word |= word << 8; 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;
|
sequential() = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM::vector(uint32 addr, Processor::Mode mode) {
|
auto ARM::vector(uint32 addr, Processor::Mode mode) -> void {
|
||||||
auto psr = cpsr();
|
auto psr = cpsr();
|
||||||
processor.setMode(mode);
|
processor.setMode(mode);
|
||||||
spsr() = psr;
|
spsr() = psr;
|
||||||
|
|
|
@ -3,44 +3,54 @@
|
||||||
|
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
//ARMv3
|
//Supported Models:
|
||||||
//ARMv4TDMI
|
//* ARMv3 (ST018)
|
||||||
|
//* ARMv4 (ARM7TDMI)
|
||||||
|
|
||||||
struct ARM {
|
struct ARM {
|
||||||
enum : unsigned { Byte = 8, Half = 16, Word = 32 };
|
enum : unsigned { Byte = 8, Half = 16, Word = 32 };
|
||||||
|
|
||||||
#include "registers.hpp"
|
#include "registers.hpp"
|
||||||
#include "instructions-arm.hpp"
|
#include "instructions-arm.hpp"
|
||||||
#include "instructions-thumb.hpp"
|
#include "instructions-thumb.hpp"
|
||||||
#include "disassembler.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();
|
virtual auto step(unsigned clocks) -> void = 0;
|
||||||
void exec();
|
virtual auto bus_idle(uint32 addr) -> void = 0;
|
||||||
void idle();
|
virtual auto bus_read(uint32 addr, uint32 size) -> uint32 = 0;
|
||||||
uint32 read(uint32 addr, uint32 size);
|
virtual auto bus_write(uint32 addr, uint32 size, uint32 word) -> void = 0;
|
||||||
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);
|
|
||||||
|
|
||||||
bool condition(uint4 condition);
|
//arm.cpp
|
||||||
uint32 bit(uint32 result);
|
auto power() -> void;
|
||||||
uint32 add(uint32 source, uint32 modify, bool carry);
|
auto exec() -> void;
|
||||||
uint32 sub(uint32 source, uint32 modify, bool carry);
|
auto idle() -> void;
|
||||||
uint32 mul(uint32 product, uint32 multiplicand, uint32 multiplier);
|
auto read(uint32 addr, uint32 size) -> uint32;
|
||||||
uint32 lsl(uint32 source, uint8 shift);
|
auto load(uint32 addr, uint32 size) -> uint32;
|
||||||
uint32 lsr(uint32 source, uint8 shift);
|
auto write(uint32 addr, uint32 size, uint32 word) -> void;
|
||||||
uint32 asr(uint32 source, uint8 shift);
|
auto store(uint32 addr, uint32 size, uint32 word) -> void;
|
||||||
uint32 ror(uint32 source, uint8 shift);
|
auto vector(uint32 addr, Processor::Mode mode) -> void;
|
||||||
uint32 rrx(uint32 source);
|
|
||||||
|
|
||||||
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;
|
//step.cpp
|
||||||
uintmax_t instructions;
|
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
|
#ifdef PROCESSOR_ARM_HPP
|
||||||
|
|
||||||
string ARM::disassemble_arm_instruction(uint32 pc) {
|
auto ARM::disassemble_arm_instruction(uint32 pc) -> string {
|
||||||
static string conditions[] = {
|
static string conditions[] = {
|
||||||
"eq", "ne", "cs", "cc",
|
"eq", "ne", "cs", "cc",
|
||||||
"mi", "pl", "vs", "vc",
|
"mi", "pl", "vs", "vc",
|
||||||
|
@ -440,7 +440,7 @@ string ARM::disassemble_arm_instruction(uint32 pc) {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
string ARM::disassemble_thumb_instruction(uint32 pc) {
|
auto ARM::disassemble_thumb_instruction(uint32 pc) -> string {
|
||||||
static string conditions[] = {
|
static string conditions[] = {
|
||||||
"eq", "ne", "cs", "cc",
|
"eq", "ne", "cs", "cc",
|
||||||
"mi", "pl", "vs", "vc",
|
"mi", "pl", "vs", "vc",
|
||||||
|
@ -761,7 +761,7 @@ string ARM::disassemble_thumb_instruction(uint32 pc) {
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
string ARM::disassemble_registers() {
|
auto ARM::disassemble_registers() -> string {
|
||||||
string output;
|
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( "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)), " ");
|
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);
|
auto disassemble_arm_instruction(uint32 pc) -> string;
|
||||||
string disassemble_thumb_instruction(uint32 pc);
|
auto disassemble_thumb_instruction(uint32 pc) -> string;
|
||||||
string disassemble_registers();
|
auto disassemble_registers() -> string;
|
||||||
|
|
|
@ -1,64 +1,6 @@
|
||||||
#ifdef PROCESSOR_ARM_HPP
|
#ifdef PROCESSOR_ARM_HPP
|
||||||
|
|
||||||
void ARM::arm_step() {
|
auto ARM::arm_opcode(uint32 rm) {
|
||||||
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) {
|
|
||||||
uint4 opcode = instruction() >> 21;
|
uint4 opcode = instruction() >> 21;
|
||||||
uint1 save = instruction() >> 20;
|
uint1 save = instruction() >> 20;
|
||||||
uint4 n = instruction() >> 16;
|
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;
|
uint1 source = instruction() >> 22;
|
||||||
uint4 field = instruction() >> 16;
|
uint4 field = instruction() >> 16;
|
||||||
|
|
||||||
|
@ -130,7 +72,7 @@ void ARM::arm_move_to_status(uint32 rm) {
|
||||||
//n = rn
|
//n = rn
|
||||||
//s = rs
|
//s = rs
|
||||||
//m = rm
|
//m = rm
|
||||||
void ARM::arm_op_multiply() {
|
auto ARM::arm_op_multiply() {
|
||||||
uint1 accumulate = instruction() >> 21;
|
uint1 accumulate = instruction() >> 21;
|
||||||
uint1 save = instruction() >> 20;
|
uint1 save = instruction() >> 20;
|
||||||
uint4 d = instruction() >> 16;
|
uint4 d = instruction() >> 16;
|
||||||
|
@ -138,7 +80,6 @@ void ARM::arm_op_multiply() {
|
||||||
uint4 s = instruction() >> 8;
|
uint4 s = instruction() >> 8;
|
||||||
uint4 m = instruction();
|
uint4 m = instruction();
|
||||||
|
|
||||||
step(1);
|
|
||||||
r(d) = mul(accumulate ? r(n) : 0u, r(m), r(s));
|
r(d) = mul(accumulate ? r(n) : 0u, r(m), r(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +94,7 @@ void ARM::arm_op_multiply() {
|
||||||
//l = rdlo
|
//l = rdlo
|
||||||
//s = rs
|
//s = rs
|
||||||
//m = rm
|
//m = rm
|
||||||
void ARM::arm_op_multiply_long() {
|
auto ARM::arm_op_multiply_long() {
|
||||||
uint1 signextend = instruction() >> 22;
|
uint1 signextend = instruction() >> 22;
|
||||||
uint1 accumulate = instruction() >> 21;
|
uint1 accumulate = instruction() >> 21;
|
||||||
uint1 save = instruction() >> 20;
|
uint1 save = instruction() >> 20;
|
||||||
|
@ -190,7 +131,7 @@ void ARM::arm_op_multiply_long() {
|
||||||
//n = rn
|
//n = rn
|
||||||
//d = rd
|
//d = rd
|
||||||
//m = rm
|
//m = rm
|
||||||
void ARM::arm_op_memory_swap() {
|
auto ARM::arm_op_memory_swap() {
|
||||||
uint1 byte = instruction() >> 22;
|
uint1 byte = instruction() >> 22;
|
||||||
uint4 n = instruction() >> 16;
|
uint4 n = instruction() >> 16;
|
||||||
uint4 d = instruction() >> 12;
|
uint4 d = instruction() >> 12;
|
||||||
|
@ -212,7 +153,7 @@ void ARM::arm_op_memory_swap() {
|
||||||
//n = rn
|
//n = rn
|
||||||
//d = rd
|
//d = rd
|
||||||
//m = rm
|
//m = rm
|
||||||
void ARM::arm_op_move_half_register() {
|
auto ARM::arm_op_move_half_register() {
|
||||||
uint1 pre = instruction() >> 24;
|
uint1 pre = instruction() >> 24;
|
||||||
uint1 up = instruction() >> 23;
|
uint1 up = instruction() >> 23;
|
||||||
uint1 writeback = instruction() >> 21;
|
uint1 writeback = instruction() >> 21;
|
||||||
|
@ -244,7 +185,7 @@ void ARM::arm_op_move_half_register() {
|
||||||
//d = rd
|
//d = rd
|
||||||
//i = immediate hi
|
//i = immediate hi
|
||||||
//i = immediate lo
|
//i = immediate lo
|
||||||
void ARM::arm_op_move_half_immediate() {
|
auto ARM::arm_op_move_half_immediate() {
|
||||||
uint1 pre = instruction() >> 24;
|
uint1 pre = instruction() >> 24;
|
||||||
uint1 up = instruction() >> 23;
|
uint1 up = instruction() >> 23;
|
||||||
uint1 writeback = instruction() >> 21;
|
uint1 writeback = instruction() >> 21;
|
||||||
|
@ -276,7 +217,7 @@ void ARM::arm_op_move_half_immediate() {
|
||||||
//d = rd
|
//d = rd
|
||||||
//h = half (0 = byte)
|
//h = half (0 = byte)
|
||||||
//m = rm
|
//m = rm
|
||||||
void ARM::arm_op_load_register() {
|
auto ARM::arm_op_load_register() {
|
||||||
uint1 pre = instruction() >> 24;
|
uint1 pre = instruction() >> 24;
|
||||||
uint1 up = instruction() >> 23;
|
uint1 up = instruction() >> 23;
|
||||||
uint1 writeback = instruction() >> 21;
|
uint1 writeback = instruction() >> 21;
|
||||||
|
@ -308,7 +249,7 @@ void ARM::arm_op_load_register() {
|
||||||
//i = immediate hi
|
//i = immediate hi
|
||||||
//h = half (0 = byte)
|
//h = half (0 = byte)
|
||||||
//i = immediate lo
|
//i = immediate lo
|
||||||
void ARM::arm_op_load_immediate() {
|
auto ARM::arm_op_load_immediate() {
|
||||||
uint1 pre = instruction() >> 24;
|
uint1 pre = instruction() >> 24;
|
||||||
uint1 up = instruction() >> 23;
|
uint1 up = instruction() >> 23;
|
||||||
uint1 writeback = instruction() >> 21;
|
uint1 writeback = instruction() >> 21;
|
||||||
|
@ -334,7 +275,7 @@ void ARM::arm_op_load_immediate() {
|
||||||
//c = condition
|
//c = condition
|
||||||
//r = SPSR (0 = CPSR)
|
//r = SPSR (0 = CPSR)
|
||||||
//d = rd
|
//d = rd
|
||||||
void ARM::arm_op_move_to_register_from_status() {
|
auto ARM::arm_op_move_to_register_from_status() {
|
||||||
uint1 source = instruction() >> 22;
|
uint1 source = instruction() >> 22;
|
||||||
uint4 d = instruction() >> 12;
|
uint4 d = instruction() >> 12;
|
||||||
|
|
||||||
|
@ -352,7 +293,7 @@ void ARM::arm_op_move_to_register_from_status() {
|
||||||
//r = SPSR (0 = CPSR)
|
//r = SPSR (0 = CPSR)
|
||||||
//f = field mask
|
//f = field mask
|
||||||
//m = rm
|
//m = rm
|
||||||
void ARM::arm_op_move_to_status_from_register() {
|
auto ARM::arm_op_move_to_status_from_register() {
|
||||||
uint4 m = instruction();
|
uint4 m = instruction();
|
||||||
|
|
||||||
arm_move_to_status(r(m));
|
arm_move_to_status(r(m));
|
||||||
|
@ -362,7 +303,7 @@ void ARM::arm_op_move_to_status_from_register() {
|
||||||
//cccc 0001 0010 ++++ ++++ ++++ 0001 mmmm
|
//cccc 0001 0010 ++++ ++++ ++++ 0001 mmmm
|
||||||
//c = condition
|
//c = condition
|
||||||
//m = rm
|
//m = rm
|
||||||
void ARM::arm_op_branch_exchange_register() {
|
auto ARM::arm_op_branch_exchange_register() {
|
||||||
uint4 m = instruction();
|
uint4 m = instruction();
|
||||||
|
|
||||||
cpsr().t = r(m) & 1;
|
cpsr().t = r(m) & 1;
|
||||||
|
@ -376,7 +317,7 @@ void ARM::arm_op_branch_exchange_register() {
|
||||||
//f = field mask
|
//f = field mask
|
||||||
//r = rotate
|
//r = rotate
|
||||||
//i = immediate
|
//i = immediate
|
||||||
void ARM::arm_op_move_to_status_from_immediate() {
|
auto ARM::arm_op_move_to_status_from_immediate() {
|
||||||
uint4 rotate = instruction() >> 8;
|
uint4 rotate = instruction() >> 8;
|
||||||
uint8 immediate = instruction();
|
uint8 immediate = instruction();
|
||||||
|
|
||||||
|
@ -398,7 +339,7 @@ void ARM::arm_op_move_to_status_from_immediate() {
|
||||||
//l = shift immediate
|
//l = shift immediate
|
||||||
//s = shift
|
//s = shift
|
||||||
//m = rm
|
//m = rm
|
||||||
void ARM::arm_op_data_immediate_shift() {
|
auto ARM::arm_op_data_immediate_shift() {
|
||||||
uint1 save = instruction() >> 20;
|
uint1 save = instruction() >> 20;
|
||||||
uint5 shift = instruction() >> 7;
|
uint5 shift = instruction() >> 7;
|
||||||
uint2 mode = instruction() >> 5;
|
uint2 mode = instruction() >> 5;
|
||||||
|
@ -428,7 +369,7 @@ void ARM::arm_op_data_immediate_shift() {
|
||||||
//s = rs
|
//s = rs
|
||||||
//s = shift
|
//s = shift
|
||||||
//m = rm
|
//m = rm
|
||||||
void ARM::arm_op_data_register_shift() {
|
auto ARM::arm_op_data_register_shift() {
|
||||||
uint1 save = instruction() >> 20;
|
uint1 save = instruction() >> 20;
|
||||||
uint4 s = instruction() >> 8;
|
uint4 s = instruction() >> 8;
|
||||||
uint2 mode = instruction() >> 5;
|
uint2 mode = instruction() >> 5;
|
||||||
|
@ -457,7 +398,7 @@ void ARM::arm_op_data_register_shift() {
|
||||||
//d = rd
|
//d = rd
|
||||||
//s = shift immediate
|
//s = shift immediate
|
||||||
//i = immediate
|
//i = immediate
|
||||||
void ARM::arm_op_data_immediate() {
|
auto ARM::arm_op_data_immediate() {
|
||||||
uint1 save = instruction() >> 20;
|
uint1 save = instruction() >> 20;
|
||||||
uint4 shift = instruction() >> 8;
|
uint4 shift = instruction() >> 8;
|
||||||
uint8 immediate = instruction();
|
uint8 immediate = instruction();
|
||||||
|
@ -482,7 +423,7 @@ void ARM::arm_op_data_immediate() {
|
||||||
//n = rn
|
//n = rn
|
||||||
//d = rd
|
//d = rd
|
||||||
//i = immediate
|
//i = immediate
|
||||||
void ARM::arm_op_move_immediate_offset() {
|
auto ARM::arm_op_move_immediate_offset() {
|
||||||
uint1 pre = instruction() >> 24;
|
uint1 pre = instruction() >> 24;
|
||||||
uint1 up = instruction() >> 23;
|
uint1 up = instruction() >> 23;
|
||||||
uint1 byte = instruction() >> 22;
|
uint1 byte = instruction() >> 22;
|
||||||
|
@ -517,7 +458,7 @@ void ARM::arm_op_move_immediate_offset() {
|
||||||
//l = shift immediate
|
//l = shift immediate
|
||||||
//s = shift mode
|
//s = shift mode
|
||||||
//m = rm
|
//m = rm
|
||||||
void ARM::arm_op_move_register_offset() {
|
auto ARM::arm_op_move_register_offset() {
|
||||||
uint1 pre = instruction() >> 24;
|
uint1 pre = instruction() >> 24;
|
||||||
uint1 up = instruction() >> 23;
|
uint1 up = instruction() >> 23;
|
||||||
uint1 byte = instruction() >> 22;
|
uint1 byte = instruction() >> 22;
|
||||||
|
@ -558,7 +499,7 @@ void ARM::arm_op_move_register_offset() {
|
||||||
//l = load (0 = save)
|
//l = load (0 = save)
|
||||||
//n = rn
|
//n = rn
|
||||||
//l = register list
|
//l = register list
|
||||||
void ARM::arm_op_move_multiple() {
|
auto ARM::arm_op_move_multiple() {
|
||||||
uint1 pre = instruction() >> 24;
|
uint1 pre = instruction() >> 24;
|
||||||
uint1 up = instruction() >> 23;
|
uint1 up = instruction() >> 23;
|
||||||
uint1 s = instruction() >> 22;
|
uint1 s = instruction() >> 22;
|
||||||
|
@ -612,7 +553,7 @@ void ARM::arm_op_move_multiple() {
|
||||||
//c = condition
|
//c = condition
|
||||||
//l = link
|
//l = link
|
||||||
//d = displacement (24-bit signed)
|
//d = displacement (24-bit signed)
|
||||||
void ARM::arm_op_branch() {
|
auto ARM::arm_op_branch() {
|
||||||
uint1 link = instruction() >> 24;
|
uint1 link = instruction() >> 24;
|
||||||
int24 displacement = instruction();
|
int24 displacement = instruction();
|
||||||
|
|
||||||
|
@ -624,7 +565,7 @@ void ARM::arm_op_branch() {
|
||||||
//cccc 1111 iiii iiii iiii iiii iiii iiii
|
//cccc 1111 iiii iiii iiii iiii iiii iiii
|
||||||
//c = condition
|
//c = condition
|
||||||
//i = immediate
|
//i = immediate
|
||||||
void ARM::arm_op_software_interrupt() {
|
auto ARM::arm_op_software_interrupt() {
|
||||||
uint24 immediate = instruction();
|
uint24 immediate = instruction();
|
||||||
|
|
||||||
vector(0x00000008, Processor::Mode::SVC);
|
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);
|
auto arm_op_multiply();
|
||||||
void arm_move_to_status(uint32 rm);
|
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();
|
auto arm_op_move_to_register_from_status();
|
||||||
void arm_op_multiply_long();
|
auto arm_op_move_to_status_from_register();
|
||||||
void arm_op_memory_swap();
|
auto arm_op_branch_exchange_register();
|
||||||
void arm_op_move_half_register();
|
|
||||||
void arm_op_move_half_immediate();
|
|
||||||
void arm_op_load_register();
|
|
||||||
void arm_op_load_immediate();
|
|
||||||
|
|
||||||
void arm_op_move_to_register_from_status();
|
auto arm_op_move_to_status_from_immediate();
|
||||||
void arm_op_move_to_status_from_register();
|
auto arm_op_data_immediate_shift();
|
||||||
void arm_op_branch_exchange_register();
|
auto arm_op_data_register_shift();
|
||||||
|
auto arm_op_data_immediate();
|
||||||
void arm_op_move_to_status_from_immediate();
|
auto arm_op_move_immediate_offset();
|
||||||
void arm_op_data_immediate_shift();
|
auto arm_op_move_register_offset();
|
||||||
void arm_op_data_register_shift();
|
auto arm_op_move_multiple();
|
||||||
void arm_op_data_immediate();
|
auto arm_op_branch();
|
||||||
void arm_op_move_immediate_offset();
|
auto arm_op_software_interrupt();
|
||||||
void arm_op_move_register_offset();
|
|
||||||
void arm_op_move_multiple();
|
|
||||||
void arm_op_branch();
|
|
||||||
void arm_op_software_interrupt();
|
|
||||||
|
|
|
@ -1,65 +1,6 @@
|
||||||
#ifdef PROCESSOR_ARM_HPP
|
#ifdef PROCESSOR_ARM_HPP
|
||||||
|
|
||||||
void ARM::thumb_step() {
|
auto ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) {
|
||||||
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) {
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
case 0: r(d) = bit(r(d) & r(m)); break; //AND
|
case 0: r(d) = bit(r(d) & r(m)); break; //AND
|
||||||
case 1: r(d) = bit(r(d) ^ r(m)); break; //EOR
|
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 10: sub(r(d), r(m), 1); break; //CMP
|
||||||
case 11: add(r(d), r(m), 0); break; //CMN
|
case 11: add(r(d), r(m), 0); break; //CMN
|
||||||
case 12: r(d) = bit(r(d) | r(m)); break; //ORR
|
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 14: r(d) = bit(r(d) & ~r(m)); break; //BIC
|
||||||
case 15: r(d) = bit(~r(m)); break; //MVN
|
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
|
//m = rm
|
||||||
//n = rn
|
//n = rn
|
||||||
//d = rd
|
//d = rd
|
||||||
void ARM::thumb_op_adjust_register() {
|
auto ARM::thumb_op_adjust_register() {
|
||||||
uint1 opcode = instruction() >> 9;
|
uint1 opcode = instruction() >> 9;
|
||||||
uint3 m = instruction() >> 6;
|
uint3 m = instruction() >> 6;
|
||||||
uint3 n = instruction() >> 3;
|
uint3 n = instruction() >> 3;
|
||||||
|
@ -104,7 +45,7 @@ void ARM::thumb_op_adjust_register() {
|
||||||
//i = immediate
|
//i = immediate
|
||||||
//n = rn
|
//n = rn
|
||||||
//d = rd
|
//d = rd
|
||||||
void ARM::thumb_op_adjust_immediate() {
|
auto ARM::thumb_op_adjust_immediate() {
|
||||||
uint1 opcode = instruction() >> 9;
|
uint1 opcode = instruction() >> 9;
|
||||||
uint3 immediate = instruction() >> 6;
|
uint3 immediate = instruction() >> 6;
|
||||||
uint3 n = instruction() >> 3;
|
uint3 n = instruction() >> 3;
|
||||||
|
@ -122,7 +63,7 @@ void ARM::thumb_op_adjust_immediate() {
|
||||||
//i = immediate
|
//i = immediate
|
||||||
//m = rm
|
//m = rm
|
||||||
//d = rd
|
//d = rd
|
||||||
void ARM::thumb_op_shift_immediate() {
|
auto ARM::thumb_op_shift_immediate() {
|
||||||
uint2 opcode = instruction() >> 11;
|
uint2 opcode = instruction() >> 11;
|
||||||
uint5 immediate = instruction() >> 6;
|
uint5 immediate = instruction() >> 6;
|
||||||
uint3 m = instruction() >> 3;
|
uint3 m = instruction() >> 3;
|
||||||
|
@ -140,7 +81,7 @@ void ARM::thumb_op_shift_immediate() {
|
||||||
//o = opcode
|
//o = opcode
|
||||||
//r = (rd,rn)
|
//r = (rd,rn)
|
||||||
//i = immediate
|
//i = immediate
|
||||||
void ARM::thumb_op_immediate() {
|
auto ARM::thumb_op_immediate() {
|
||||||
uint2 opcode = instruction() >> 11;
|
uint2 opcode = instruction() >> 11;
|
||||||
uint3 d = instruction() >> 8;
|
uint3 d = instruction() >> 8;
|
||||||
uint8 immediate = instruction();
|
uint8 immediate = instruction();
|
||||||
|
@ -158,7 +99,7 @@ void ARM::thumb_op_immediate() {
|
||||||
//o = opcode
|
//o = opcode
|
||||||
//m = rm
|
//m = rm
|
||||||
//d = rd
|
//d = rd
|
||||||
void ARM::thumb_op_alu() {
|
auto ARM::thumb_op_alu() {
|
||||||
uint4 opcode = instruction() >> 6;
|
uint4 opcode = instruction() >> 6;
|
||||||
uint3 m = instruction() >> 3;
|
uint3 m = instruction() >> 3;
|
||||||
uint3 d = instruction();
|
uint3 d = instruction();
|
||||||
|
@ -169,7 +110,7 @@ void ARM::thumb_op_alu() {
|
||||||
//bx rm
|
//bx rm
|
||||||
//0100 0111 0mmm m---
|
//0100 0111 0mmm m---
|
||||||
//m = rm
|
//m = rm
|
||||||
void ARM::thumb_op_branch_exchange() {
|
auto ARM::thumb_op_branch_exchange() {
|
||||||
uint4 m = instruction() >> 3;
|
uint4 m = instruction() >> 3;
|
||||||
|
|
||||||
cpsr().t = r(m) & 1;
|
cpsr().t = r(m) & 1;
|
||||||
|
@ -181,7 +122,7 @@ void ARM::thumb_op_branch_exchange() {
|
||||||
//o = opcode
|
//o = opcode
|
||||||
//M:m = rm
|
//M:m = rm
|
||||||
//D:d = rd
|
//D:d = rd
|
||||||
void ARM::thumb_op_alu_hi() {
|
auto ARM::thumb_op_alu_hi() {
|
||||||
uint2 opcode = instruction() >> 8;
|
uint2 opcode = instruction() >> 8;
|
||||||
uint4 m = instruction() >> 3;
|
uint4 m = instruction() >> 3;
|
||||||
uint3 dl = instruction();
|
uint3 dl = instruction();
|
||||||
|
@ -199,7 +140,7 @@ void ARM::thumb_op_alu_hi() {
|
||||||
//0100 1ddd oooo oooo
|
//0100 1ddd oooo oooo
|
||||||
//d = rd
|
//d = rd
|
||||||
//o = offset
|
//o = offset
|
||||||
void ARM::thumb_op_load_literal() {
|
auto ARM::thumb_op_load_literal() {
|
||||||
uint3 d = instruction() >> 8;
|
uint3 d = instruction() >> 8;
|
||||||
uint8 displacement = instruction();
|
uint8 displacement = instruction();
|
||||||
|
|
||||||
|
@ -213,7 +154,7 @@ void ARM::thumb_op_load_literal() {
|
||||||
//m = rm
|
//m = rm
|
||||||
//n = rn
|
//n = rn
|
||||||
//d = rd
|
//d = rd
|
||||||
void ARM::thumb_op_move_register_offset() {
|
auto ARM::thumb_op_move_register_offset() {
|
||||||
uint3 opcode = instruction() >> 9;
|
uint3 opcode = instruction() >> 9;
|
||||||
uint3 m = instruction() >> 6;
|
uint3 m = instruction() >> 6;
|
||||||
uint3 n = instruction() >> 3;
|
uint3 n = instruction() >> 3;
|
||||||
|
@ -237,7 +178,7 @@ void ARM::thumb_op_move_register_offset() {
|
||||||
//o = offset
|
//o = offset
|
||||||
//n = rn
|
//n = rn
|
||||||
//d = rd
|
//d = rd
|
||||||
void ARM::thumb_op_move_word_immediate() {
|
auto ARM::thumb_op_move_word_immediate() {
|
||||||
uint1 l = instruction() >> 11;
|
uint1 l = instruction() >> 11;
|
||||||
uint5 offset = instruction() >> 6;
|
uint5 offset = instruction() >> 6;
|
||||||
uint3 n = instruction() >> 3;
|
uint3 n = instruction() >> 3;
|
||||||
|
@ -253,7 +194,7 @@ void ARM::thumb_op_move_word_immediate() {
|
||||||
//o = offset
|
//o = offset
|
||||||
//n = rn
|
//n = rn
|
||||||
//d = rd
|
//d = rd
|
||||||
void ARM::thumb_op_move_byte_immediate() {
|
auto ARM::thumb_op_move_byte_immediate() {
|
||||||
uint1 l = instruction() >> 11;
|
uint1 l = instruction() >> 11;
|
||||||
uint5 offset = instruction() >> 6;
|
uint5 offset = instruction() >> 6;
|
||||||
uint3 n = instruction() >> 3;
|
uint3 n = instruction() >> 3;
|
||||||
|
@ -269,7 +210,7 @@ void ARM::thumb_op_move_byte_immediate() {
|
||||||
//o = offset
|
//o = offset
|
||||||
//n = rn
|
//n = rn
|
||||||
//d = rd
|
//d = rd
|
||||||
void ARM::thumb_op_move_half_immediate() {
|
auto ARM::thumb_op_move_half_immediate() {
|
||||||
uint1 l = instruction() >> 11;
|
uint1 l = instruction() >> 11;
|
||||||
uint5 offset = instruction() >> 6;
|
uint5 offset = instruction() >> 6;
|
||||||
uint3 n = instruction() >> 3;
|
uint3 n = instruction() >> 3;
|
||||||
|
@ -284,7 +225,7 @@ void ARM::thumb_op_move_half_immediate() {
|
||||||
//l = load
|
//l = load
|
||||||
//d = rd
|
//d = rd
|
||||||
//i = immediate
|
//i = immediate
|
||||||
void ARM::thumb_op_move_stack() {
|
auto ARM::thumb_op_move_stack() {
|
||||||
uint1 l = instruction() >> 11;
|
uint1 l = instruction() >> 11;
|
||||||
uint3 d = instruction() >> 8;
|
uint3 d = instruction() >> 8;
|
||||||
uint8 immediate = instruction();
|
uint8 immediate = instruction();
|
||||||
|
@ -298,7 +239,7 @@ void ARM::thumb_op_move_stack() {
|
||||||
//s = sp (0 = pc)
|
//s = sp (0 = pc)
|
||||||
//d = rd
|
//d = rd
|
||||||
//i = immediate
|
//i = immediate
|
||||||
void ARM::thumb_op_add_register_hi() {
|
auto ARM::thumb_op_add_register_hi() {
|
||||||
uint1 sp = instruction() >> 11;
|
uint1 sp = instruction() >> 11;
|
||||||
uint3 d = instruction() >> 8;
|
uint3 d = instruction() >> 8;
|
||||||
uint8 immediate = instruction();
|
uint8 immediate = instruction();
|
||||||
|
@ -311,7 +252,7 @@ void ARM::thumb_op_add_register_hi() {
|
||||||
//1011 0000 oiii iiii
|
//1011 0000 oiii iiii
|
||||||
//o = opcode
|
//o = opcode
|
||||||
//i = immediate
|
//i = immediate
|
||||||
void ARM::thumb_op_adjust_stack() {
|
auto ARM::thumb_op_adjust_stack() {
|
||||||
uint1 opcode = instruction() >> 7;
|
uint1 opcode = instruction() >> 7;
|
||||||
uint7 immediate = instruction();
|
uint7 immediate = instruction();
|
||||||
|
|
||||||
|
@ -325,7 +266,7 @@ void ARM::thumb_op_adjust_stack() {
|
||||||
//o = opcode (0 = push, 1 = pop)
|
//o = opcode (0 = push, 1 = pop)
|
||||||
//r = push lr -or- pop pc
|
//r = push lr -or- pop pc
|
||||||
//l = register list
|
//l = register list
|
||||||
void ARM::thumb_op_stack_multiple() {
|
auto ARM::thumb_op_stack_multiple() {
|
||||||
uint1 l = instruction() >> 11;
|
uint1 l = instruction() >> 11;
|
||||||
uint1 branch = instruction() >> 8;
|
uint1 branch = instruction() >> 8;
|
||||||
uint8 list = instruction();
|
uint8 list = instruction();
|
||||||
|
@ -336,7 +277,7 @@ void ARM::thumb_op_stack_multiple() {
|
||||||
|
|
||||||
sequential() = false;
|
sequential() = false;
|
||||||
for(unsigned m = 0; m < 8; m++) {
|
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 == 1) r(m) = read(sp, Word); //POP
|
||||||
if(l == 0) write(sp, Word, r(m)); //PUSH
|
if(l == 0) write(sp, Word, r(m)); //PUSH
|
||||||
sp += 4;
|
sp += 4;
|
||||||
|
@ -360,27 +301,29 @@ void ARM::thumb_op_stack_multiple() {
|
||||||
//l = load (0 = save)
|
//l = load (0 = save)
|
||||||
//n = rn
|
//n = rn
|
||||||
//l = register list
|
//l = register list
|
||||||
void ARM::thumb_op_move_multiple() {
|
auto ARM::thumb_op_move_multiple() {
|
||||||
uint1 l = instruction() >> 11;
|
uint1 l = instruction() >> 11;
|
||||||
uint3 n = instruction() >> 8;
|
uint3 n = instruction() >> 8;
|
||||||
uint8 list = instruction();
|
uint8 list = instruction();
|
||||||
|
uint32 rn = r(n); //rn may be in register list; so we must cache it
|
||||||
|
|
||||||
sequential() = false;
|
sequential() = false;
|
||||||
for(unsigned m = 0; m < 8; m++) {
|
for(unsigned m = 0; m < 8; m++) {
|
||||||
if(list & (1 << m)) {
|
if(list & 1 << m) {
|
||||||
if(l == 1) r(m) = read(r(n), Word); //LDMIA
|
if(l == 1) r(m) = read(rn, Word); //LDMIA
|
||||||
if(l == 0) write(r(n), Word, r(m)); //STMIA
|
if(l == 0) write(rn, Word, r(m)); //STMIA
|
||||||
r(n) += 4;
|
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();
|
if(l == 1) idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
//swi #immediate
|
//swi #immediate
|
||||||
//1101 1111 iiii iiii
|
//1101 1111 iiii iiii
|
||||||
//i = immediate
|
//i = immediate
|
||||||
void ARM::thumb_op_software_interrupt() {
|
auto ARM::thumb_op_software_interrupt() {
|
||||||
uint8 immediate = instruction();
|
uint8 immediate = instruction();
|
||||||
|
|
||||||
vector(0x00000008, Processor::Mode::SVC);
|
vector(0x00000008, Processor::Mode::SVC);
|
||||||
|
@ -390,7 +333,7 @@ void ARM::thumb_op_software_interrupt() {
|
||||||
//1101 cccc dddd dddd
|
//1101 cccc dddd dddd
|
||||||
//c = condition
|
//c = condition
|
||||||
//d = displacement
|
//d = displacement
|
||||||
void ARM::thumb_op_branch_conditional() {
|
auto ARM::thumb_op_branch_conditional() {
|
||||||
uint4 flagcondition = instruction() >> 8;
|
uint4 flagcondition = instruction() >> 8;
|
||||||
int8 displacement = instruction();
|
int8 displacement = instruction();
|
||||||
|
|
||||||
|
@ -401,7 +344,7 @@ void ARM::thumb_op_branch_conditional() {
|
||||||
//b address
|
//b address
|
||||||
//1110 0ooo oooo oooo
|
//1110 0ooo oooo oooo
|
||||||
//o = offset
|
//o = offset
|
||||||
void ARM::thumb_op_branch_short() {
|
auto ARM::thumb_op_branch_short() {
|
||||||
int11 displacement = instruction();
|
int11 displacement = instruction();
|
||||||
|
|
||||||
r(15) += displacement * 2;
|
r(15) += displacement * 2;
|
||||||
|
@ -410,7 +353,7 @@ void ARM::thumb_op_branch_short() {
|
||||||
//bl address
|
//bl address
|
||||||
//1111 0ooo oooo oooo
|
//1111 0ooo oooo oooo
|
||||||
//o = offset
|
//o = offset
|
||||||
void ARM::thumb_op_branch_long_prefix() {
|
auto ARM::thumb_op_branch_long_prefix() {
|
||||||
int11 offsethi = instruction();
|
int11 offsethi = instruction();
|
||||||
|
|
||||||
r(14) = r(15) + ((offsethi * 2) << 11);
|
r(14) = r(15) + ((offsethi * 2) << 11);
|
||||||
|
@ -419,7 +362,7 @@ void ARM::thumb_op_branch_long_prefix() {
|
||||||
//bl address
|
//bl address
|
||||||
//1111 1ooo oooo oooo
|
//1111 1ooo oooo oooo
|
||||||
//o = offset
|
//o = offset
|
||||||
void ARM::thumb_op_branch_long_suffix() {
|
auto ARM::thumb_op_branch_long_suffix() {
|
||||||
uint11 offsetlo = instruction();
|
uint11 offsetlo = instruction();
|
||||||
|
|
||||||
r(15) = r(14) + (offsetlo * 2);
|
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);
|
auto thumb_op_adjust_register();
|
||||||
|
auto thumb_op_adjust_immediate();
|
||||||
void thumb_op_adjust_register();
|
auto thumb_op_shift_immediate();
|
||||||
void thumb_op_adjust_immediate();
|
auto thumb_op_immediate();
|
||||||
void thumb_op_shift_immediate();
|
auto thumb_op_alu();
|
||||||
void thumb_op_immediate();
|
auto thumb_op_branch_exchange();
|
||||||
void thumb_op_alu();
|
auto thumb_op_alu_hi();
|
||||||
void thumb_op_branch_exchange();
|
auto thumb_op_load_literal();
|
||||||
void thumb_op_alu_hi();
|
auto thumb_op_move_register_offset();
|
||||||
void thumb_op_load_literal();
|
auto thumb_op_move_word_immediate();
|
||||||
void thumb_op_move_register_offset();
|
auto thumb_op_move_byte_immediate();
|
||||||
void thumb_op_move_word_immediate();
|
auto thumb_op_move_half_immediate();
|
||||||
void thumb_op_move_byte_immediate();
|
auto thumb_op_move_stack();
|
||||||
void thumb_op_move_half_immediate();
|
auto thumb_op_add_register_hi();
|
||||||
void thumb_op_move_stack();
|
auto thumb_op_adjust_stack();
|
||||||
void thumb_op_add_register_hi();
|
auto thumb_op_stack_multiple();
|
||||||
void thumb_op_adjust_stack();
|
auto thumb_op_move_multiple();
|
||||||
void thumb_op_stack_multiple();
|
auto thumb_op_software_interrupt();
|
||||||
void thumb_op_move_multiple();
|
auto thumb_op_branch_conditional();
|
||||||
void thumb_op_software_interrupt();
|
auto thumb_op_branch_short();
|
||||||
void thumb_op_branch_conditional();
|
auto thumb_op_branch_long_prefix();
|
||||||
void thumb_op_branch_short();
|
auto thumb_op_branch_long_suffix();
|
||||||
void thumb_op_branch_long_prefix();
|
|
||||||
void thumb_op_branch_long_suffix();
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#ifdef PROCESSOR_ARM_HPP
|
#ifdef PROCESSOR_ARM_HPP
|
||||||
|
|
||||||
void ARM::Processor::power() {
|
auto ARM::Processor::power() -> void {
|
||||||
r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = 0;
|
r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = 0;
|
||||||
usr.r8 = usr.r9 = usr.r10 = usr.r11 = usr.r12 = usr.sp = usr.lr = 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;
|
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;
|
r[15] = &pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM::Processor::setMode(Mode mode) {
|
auto ARM::Processor::setMode(Mode mode) -> void {
|
||||||
cpsr.m = 0x10 | (unsigned)mode;
|
cpsr.m = 0x10 | (unsigned)mode;
|
||||||
|
|
||||||
if(mode == Mode::FIQ) {
|
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.execute = pipeline.decode;
|
||||||
pipeline.decode = pipeline.fetch;
|
pipeline.decode = pipeline.fetch;
|
||||||
|
|
||||||
|
|
|
@ -1,39 +1,30 @@
|
||||||
struct GPR {
|
struct GPR {
|
||||||
uint32 data;
|
|
||||||
function<void ()> modify;
|
|
||||||
|
|
||||||
inline operator uint32() const { return data; }
|
inline operator uint32() const { return data; }
|
||||||
inline GPR& operator=(uint32 n) { data = n; if(modify) modify(); return *this; }
|
inline auto operator=(uint32 n) { data = n; if(modify) modify(); return *this; }
|
||||||
inline GPR& operator=(const GPR& source) { return operator=(source.data); }
|
inline auto operator=(const GPR& source) { return operator=(source.data); }
|
||||||
|
|
||||||
inline GPR& operator &=(uint32 n) { return operator=(data & n); }
|
inline auto 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 GPR& operator ^=(uint32 n) { return operator=(data ^ n); }
|
inline auto 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 GPR& operator -=(uint32 n) { return operator=(data - n); }
|
inline auto 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 GPR& operator /=(uint32 n) { return operator=(data / n); }
|
inline auto 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 GPR& operator<<=(uint32 n) { return operator=(data << n); }
|
inline auto 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); }
|
||||||
|
|
||||||
|
uint32 data{0};
|
||||||
|
function<void ()> modify;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PSR {
|
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 {
|
inline operator uint32() const {
|
||||||
return (n << 31) + (z << 30) + (c << 29) + (v << 28)
|
return (n << 31) + (z << 30) + (c << 29) + (v << 28)
|
||||||
+ (i << 7) + (f << 6) + (t << 5) + (m << 0);
|
+ (i << 7) + (f << 6) + (t << 5) + (m << 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PSR& operator=(uint32 d) {
|
inline auto operator=(uint32 d) {
|
||||||
n = d & (1 << 31);
|
n = d & (1 << 31);
|
||||||
z = d & (1 << 30);
|
z = d & (1 << 30);
|
||||||
c = d & (1 << 29);
|
c = d & (1 << 29);
|
||||||
|
@ -45,15 +36,24 @@ struct PSR {
|
||||||
return *this;
|
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 {
|
struct Pipeline {
|
||||||
bool reload;
|
bool reload{false};
|
||||||
|
|
||||||
struct Instruction {
|
struct Instruction {
|
||||||
uint32 address;
|
uint32 address{0};
|
||||||
uint32 instruction;
|
uint32 instruction{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
Instruction execute;
|
Instruction execute;
|
||||||
|
@ -105,29 +105,29 @@ struct Processor {
|
||||||
|
|
||||||
GPR pc;
|
GPR pc;
|
||||||
PSR cpsr;
|
PSR cpsr;
|
||||||
bool carryout;
|
bool carryout{false};
|
||||||
bool sequential;
|
bool sequential{false};
|
||||||
bool irqline;
|
bool irqline{false};
|
||||||
|
|
||||||
GPR* r[16];
|
GPR* r[16];
|
||||||
PSR* spsr;
|
PSR* spsr;
|
||||||
|
|
||||||
void power();
|
auto power() -> void;
|
||||||
void setMode(Mode);
|
auto setMode(Mode) -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
Processor processor;
|
Processor processor;
|
||||||
Pipeline pipeline;
|
Pipeline pipeline;
|
||||||
bool crash;
|
bool crash{false};
|
||||||
|
|
||||||
void pipeline_step();
|
auto pipeline_step() -> void;
|
||||||
|
|
||||||
alwaysinline GPR& r(unsigned n) { return *processor.r[n]; }
|
alwaysinline auto r(unsigned n) -> GPR& { return *processor.r[n]; }
|
||||||
alwaysinline PSR& cpsr() { return processor.cpsr; }
|
alwaysinline auto cpsr() -> PSR& { return processor.cpsr; }
|
||||||
alwaysinline PSR& spsr() { return *processor.spsr; }
|
alwaysinline auto spsr() -> PSR& { return *processor.spsr; }
|
||||||
alwaysinline bool& carryout() { return processor.carryout; }
|
alwaysinline auto carryout() -> bool& { return processor.carryout; }
|
||||||
alwaysinline bool& sequential() { return processor.sequential; }
|
alwaysinline auto sequential() -> bool& { return processor.sequential; }
|
||||||
alwaysinline uint32 instruction() { return pipeline.execute.instruction; }
|
alwaysinline auto instruction() -> uint32 { return pipeline.execute.instruction; }
|
||||||
alwaysinline Processor::Mode mode() { return (Processor::Mode)processor.cpsr.m; }
|
alwaysinline auto mode() -> Processor::Mode { return (Processor::Mode)processor.cpsr.m; }
|
||||||
alwaysinline bool privilegedmode() const { return (Processor::Mode)processor.cpsr.m != Processor::Mode::USR; }
|
alwaysinline auto privilegedmode() const -> bool { 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 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(n);
|
||||||
s.integer(z);
|
s.integer(z);
|
||||||
s.integer(c);
|
s.integer(c);
|
||||||
|
@ -9,7 +9,7 @@ void ARM::PSR::serialize(serializer& s) {
|
||||||
s.integer(m);
|
s.integer(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM::serialize(serializer& s) {
|
auto ARM::serialize(serializer& s) -> void {
|
||||||
s.integer(processor.r0.data);
|
s.integer(processor.r0.data);
|
||||||
s.integer(processor.r1.data);
|
s.integer(processor.r1.data);
|
||||||
s.integer(processor.r2.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