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:
Tim Allen 2015-06-24 23:21:24 +10:00
parent 83f684c66c
commit 310ff4fa3b
22 changed files with 384 additions and 371 deletions

View File

@ -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/";

View File

@ -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);
} }

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;

View File

@ -1,3 +1,3 @@
void Bus::serialize(serializer& s) { auto Bus::serialize(serializer& s) -> void {
s.integer(idleflag); s.integer(idleflag);
} }

View File

@ -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; }

View File

@ -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);
} }

View File

@ -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;

View File

@ -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};
}; };
} }

View File

@ -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)), " ");

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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; }

View File

@ -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);

116
processor/arm/step.cpp Normal file
View File

@ -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;
}