mirror of https://github.com/bsnes-emu/bsnes.git
Update to v087r10 release.
byuu says: Changelog: - fixed THUMB hi immediate reads (immediate * 4) - cartridge is properly mirrored to 32MB (eg 12mbit repeats as lo8+hi4+hi4+lo8+hi4+hi4) [so it's a bit slower than a standard memcpy fill] - added ARM - load/store halfword register offset - added ARM - load/store halfword immediate offset - added ARM - load signed halfword/byte register offset - added ARM - load signed halfword/byte immediate offset - added decode() function to make opcode bit testing a lot clearer (didn't apply it to the debugger yet) All ARMv4M and all THUMBv4 instructions should now be implemented. Although I'm not sure if my implementations of the new instructions are correct.
This commit is contained in:
parent
e16dd58184
commit
5a1dcf5079
|
@ -1,7 +1,7 @@
|
|||
#ifndef BASE_HPP
|
||||
#define BASE_HPP
|
||||
|
||||
static const char Version[] = "087.09";
|
||||
static const char Version[] = "087.10";
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
|
|
|
@ -6,8 +6,10 @@ Cartridge cartridge;
|
|||
|
||||
bool Cartridge::load(const string &markup, const uint8_t *data, unsigned size) {
|
||||
if(cartridge.rom.data) delete[] cartridge.rom.data;
|
||||
cartridge.rom.data = new uint8[cartridge.rom.size = size];
|
||||
memcpy(cartridge.rom.data, data, size);
|
||||
cartridge.rom.data = new uint8[cartridge.rom.size = 32 * 1024 * 1024];
|
||||
for(unsigned addr = 0; addr < 32 * 1024 * 1024; addr++) {
|
||||
cartridge.rom.data[addr] = data[Bus::mirror(addr, size)];
|
||||
}
|
||||
|
||||
if(cartridge.ram.data) delete[] cartridge.ram.data;
|
||||
cartridge.ram.data = new uint8[cartridge.ram.size = 64 * 1024]();
|
||||
|
|
|
@ -12,6 +12,7 @@ void CPU::enter() {
|
|||
print(cpsr().t ? disassemble_thumb_instruction(pipeline.execute.address)
|
||||
: disassemble_arm_instruction(pipeline.execute.address), "\n");
|
||||
print(disassemble_registers(), "\n");
|
||||
print("Executed: ", instructions, "\n");
|
||||
while(true) step(frequency);
|
||||
}
|
||||
cpsr().t ? thumb_step() : arm_step();
|
||||
|
|
|
@ -5,8 +5,8 @@ namespace GBA {
|
|||
Bus bus;
|
||||
|
||||
struct UnmappedMemory : Memory {
|
||||
uint32 read(uint32 addr, uint32 size) { print(hex<8>(addr), ":", decimal<2>(size), "\n"); return 0u; }
|
||||
void write(uint32 addr, uint32 size, uint32 word) { print(hex<8>(addr), ":", decimal<2>(size), "=", hex<8>(word), "\n"); }
|
||||
uint32 read(uint32 addr, uint32 size) { return 0u; }
|
||||
void write(uint32 addr, uint32 size, uint32 word) {}
|
||||
};
|
||||
|
||||
static UnmappedMemory unmappedMemory;
|
||||
|
@ -66,6 +66,24 @@ StaticMemory::~StaticMemory() {
|
|||
|
||||
//
|
||||
|
||||
uint32 Bus::mirror(uint32 addr, uint32 size) {
|
||||
uint32 base = 0;
|
||||
if(size) {
|
||||
uint32 mask = 1 << 27; //28-bit bus
|
||||
while(addr >= size) {
|
||||
while(!(addr & mask)) mask >>= 1;
|
||||
addr -= mask;
|
||||
if(size > mask) {
|
||||
size -= mask;
|
||||
base += mask;
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
base += addr;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
uint32 Bus::read(uint32 addr, uint32 size) {
|
||||
switch(addr & 0x0f000000) {
|
||||
case 0x00000000: return system.bios.read(addr & 0x3fff, size);
|
||||
|
|
|
@ -15,6 +15,7 @@ struct StaticMemory : Memory {
|
|||
|
||||
struct Bus : Memory {
|
||||
Memory *mmio[0x400];
|
||||
static uint32 mirror(uint32 addr, uint32 size);
|
||||
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
|
|
|
@ -27,6 +27,24 @@ namespace nall {
|
|||
}
|
||||
|
||||
namespace bit {
|
||||
constexpr inline uintmax_t mask(const char *s, uintmax_t sum = 0) {
|
||||
return (
|
||||
*s == '0' || *s == '1' ? mask(s + 1, (sum << 1) | 1) :
|
||||
*s == ' ' || *s == '_' ? mask(s + 1, sum) :
|
||||
*s ? mask(s + 1, sum << 1) :
|
||||
sum
|
||||
);
|
||||
}
|
||||
|
||||
constexpr inline uintmax_t test(const char *s, uintmax_t sum = 0) {
|
||||
return (
|
||||
*s == '0' || *s == '1' ? test(s + 1, (sum << 1) | (*s - '0')) :
|
||||
*s == ' ' || *s == '_' ? test(s + 1, sum) :
|
||||
*s ? test(s + 1, sum << 1) :
|
||||
sum
|
||||
);
|
||||
}
|
||||
|
||||
//lowest(0b1110) == 0b0010
|
||||
constexpr inline uintmax_t lowest(const uintmax_t x) {
|
||||
return x & -x;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
//user-defined literals
|
||||
|
||||
#include <nall/atoi.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace nall {
|
||||
constexpr inline uintmax_t operator"" _b(const char *n) { return binary(n); }
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
bool ARM::condition(uint4 condition) {
|
||||
switch(condition) {
|
||||
case 0: return cpsr().z == 1; //EQ (equal)
|
||||
case 1: return cpsr().z == 0; //NE (not equal)
|
||||
case 2: return cpsr().c == 1; //CS (carry set)
|
||||
case 3: return cpsr().c == 0; //CC (carry clear)
|
||||
case 4: return cpsr().n == 1; //MI (negative)
|
||||
case 5: return cpsr().n == 0; //PL (positive)
|
||||
case 6: return cpsr().v == 1; //VS (overflow)
|
||||
case 7: return cpsr().v == 0; //VC (no overflow)
|
||||
case 8: return cpsr().c == 1 && cpsr().z == 0; //HI (unsigned higher)
|
||||
case 9: return cpsr().c == 0 || cpsr().z == 1; //LS (unsigned lower or same)
|
||||
case 10: return cpsr().n == cpsr().v; //GE (signed greater than or equal)
|
||||
case 11: return cpsr().n != cpsr().v; //LT (signed less than)
|
||||
case 12: return cpsr().z == 0 && cpsr().n == cpsr().v; //GT (signed greater than)
|
||||
case 13: return cpsr().z == 1 || cpsr().n != cpsr().v; //LE (signed less than or equal)
|
||||
case 14: return true; //AL (always)
|
||||
case 15: return false; //NV (never)
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
namespace Processor {
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "algorithms.cpp"
|
||||
#include "instructions-arm.cpp"
|
||||
#include "instructions-thumb.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
@ -17,6 +18,9 @@ void ARM::power() {
|
|||
pipeline.reload = true;
|
||||
r(15).data &= cpsr().t ? ~1 : ~3;
|
||||
};
|
||||
|
||||
trace = false;
|
||||
instructions = 0;
|
||||
}
|
||||
|
||||
void ARM::vector(uint32 addr, Processor::Mode mode) {
|
||||
|
|
|
@ -17,8 +17,12 @@ struct ARM {
|
|||
|
||||
void power();
|
||||
void vector(uint32 addr, Processor::Mode mode);
|
||||
bool condition(uint4 condition);
|
||||
|
||||
void serialize(serializer&);
|
||||
|
||||
bool trace;
|
||||
uintmax_t instructions;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -54,19 +54,6 @@ string ARM::disassemble_arm_instruction(uint32 pc) {
|
|||
return output;
|
||||
}
|
||||
|
||||
//move_to_register_from_status()
|
||||
//mrs{condition} rd,(c,s)psr
|
||||
if((instruction & 0x0fb000f0) == 0x01000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 psr = instruction >> 22;
|
||||
uint4 rd = instruction >> 12;
|
||||
|
||||
output.append("mrs", conditions[condition], " ");
|
||||
output.append(registers[rd], ",", psr ? "spsr" : "cpsr");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//memory_swap()
|
||||
//swp{condition}{b} rd,rm,[rn]
|
||||
if((instruction & 0x0fb000f0) == 0x01000090) {
|
||||
|
@ -82,6 +69,120 @@ string ARM::disassemble_arm_instruction(uint32 pc) {
|
|||
return output;
|
||||
}
|
||||
|
||||
//move_half_register()
|
||||
//(ldr,str){condition}h rd,[rn,rm]{!}
|
||||
//(ldr,str){condition}h rd,[rn],rm
|
||||
if((instruction & 0x0e4000f0) == 0x000000b0) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 pre = instruction >> 24;
|
||||
uint1 up = instruction >> 23;
|
||||
uint1 writeback = instruction >> 21;
|
||||
uint1 load = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint4 rm = instruction;
|
||||
|
||||
output.append(load ? "ldr" : "str", conditions[condition], "h ");
|
||||
output.append(registers[rd], ",[", registers[rn]);
|
||||
if(pre == 0) output.append("]");
|
||||
output.append(",", up ? "+" : "-", registers[rm]);
|
||||
if(pre == 1) output.append("]");
|
||||
if(pre == 0 || writeback == 1) output.append("!");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//move_half_immediate()
|
||||
//(ldr,str){condition}h rd,[rd{,+/-offset}]{!}
|
||||
//(ldr,str){condition}h rd,[rn]{,+/-offset}
|
||||
if((instruction & 0x0e4000f0) == 0x004000b0) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 pre = instruction >> 24;
|
||||
uint1 up = instruction >> 23;
|
||||
uint1 writeback = instruction >> 21;
|
||||
uint1 load = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint4 ih = instruction >> 8;
|
||||
uint4 il = instruction >> 0;
|
||||
|
||||
uint8 immediate = (ih << 4) + (il << 0);
|
||||
|
||||
output.append(load ? "ldr" : "str", conditions[condition], "h ");
|
||||
output.append(registers[rd], ",[", registers[rn]);
|
||||
if(pre == 0) output.append("]");
|
||||
if(immediate) output.append(",", up ? "+" : "-", "0x", hex<2>(immediate));
|
||||
if(pre == 1) output.append("]");
|
||||
if(pre == 0 || writeback == 1) output.append("!");
|
||||
|
||||
if(rn == 15) output.append(" =0x", hex<4>(bus_read(pc + 8 + (up ? +immediate : -immediate), Half)));
|
||||
return output;
|
||||
}
|
||||
|
||||
//load_register()
|
||||
//ldr{condition}s(h,b) rd,[rn,rm]{!}
|
||||
//ldr{condition}s(h,b) rd,[rn],rm
|
||||
if((instruction & 0x0e5000d0) == 0x001000b0) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 pre = instruction >> 24;
|
||||
uint1 up = instruction >> 23;
|
||||
uint1 writeback = instruction >> 21;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint1 half = instruction >> 5;
|
||||
uint4 rm = instruction;
|
||||
|
||||
output.append("ldr", conditions[condition], half ? "sh " : "sb ");
|
||||
output.append(registers[rd], ",[", registers[rn]);
|
||||
if(pre == 0) output.append("]");
|
||||
output.append(",", up ? "+" : "-", registers[rm]);
|
||||
if(pre == 1) output.append("]");
|
||||
if(pre == 0 || writeback == 1) output.append("!");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//load_immediate()
|
||||
//ldr{condition}s(h,b) rd,[rn{,+/-offset}]{!}
|
||||
//ldr{condition}s(h,b) rd,[rn]{,+/-offset}
|
||||
if((instruction & 0x0e5000b0) == 0x005000b0) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 pre = instruction >> 24;
|
||||
uint1 up = instruction >> 23;
|
||||
uint1 writeback = instruction >> 21;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint4 ih = instruction >> 8;
|
||||
uint1 half = instruction >> 5;
|
||||
uint4 il = instruction;
|
||||
|
||||
uint8 immediate = (ih << 4) + (il << 0);
|
||||
|
||||
output.append("ldr", conditions[condition], half ? "sh " : "sb ");
|
||||
output.append(registers[rd], ",[", registers[rn]);
|
||||
if(pre == 0) output.append("]");
|
||||
if(immediate) output.append(",", up ? "+" : "-", "0x", hex<2>(immediate));
|
||||
if(pre == 1) output.append("]");
|
||||
if(pre == 0 || writeback == 1) output.append("!");
|
||||
|
||||
if(rn == 15 && half == 1) output.append(" =0x", hex<4>(bus_read(pc + 8 + (up ? +immediate : -immediate), Half)));
|
||||
if(rn == 15 && half == 0) output.append(" =0x", hex<2>(bus_read(pc + 8 + (up ? +immediate : -immediate), Byte)));
|
||||
return output;
|
||||
}
|
||||
|
||||
//move_to_register_from_status()
|
||||
//mrs{condition} rd,(c,s)psr
|
||||
if((instruction & 0x0fb000f0) == 0x01000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 psr = instruction >> 22;
|
||||
uint4 rd = instruction >> 12;
|
||||
|
||||
output.append("mrs", conditions[condition], " ");
|
||||
output.append(registers[rd], ",", psr ? "spsr" : "cpsr");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//move_to_status_from_register()
|
||||
//msr{condition} (c,s)psr:{fields},rm
|
||||
if((instruction & 0x0fb000f0) == 0x01200000) {
|
||||
|
|
|
@ -21,53 +21,45 @@ void ARM::arm_step() {
|
|||
pipeline.fetch.instruction = bus_read(r(15), Word);
|
||||
step(2);
|
||||
|
||||
//print(disassemble_registers(), "\n");
|
||||
//print(disassemble_arm_instruction(pipeline.execute.address), "\n");
|
||||
instructions++;
|
||||
if(trace) {
|
||||
print(disassemble_registers(), "\n");
|
||||
print(disassemble_arm_instruction(pipeline.execute.address), "\n");
|
||||
}
|
||||
|
||||
if(arm_condition() == false) return;
|
||||
if(condition(instruction() >> 28) == false) return;
|
||||
|
||||
if((instruction() & 0x0fc000f0) == 0x00000090) { arm_op_multiply(); return; }
|
||||
if((instruction() & 0x0fb000f0) == 0x01000000) { arm_op_move_to_register_from_status(); return; }
|
||||
if((instruction() & 0x0fb000f0) == 0x01000090) { arm_op_memory_swap(); return; }
|
||||
if((instruction() & 0x0fb000f0) == 0x01200000) { arm_op_move_to_status_from_register(); return; }
|
||||
if((instruction() & 0x0ff000f0) == 0x01200010) { arm_op_branch_exchange_register(); return; } //ARMv4+
|
||||
if((instruction() & 0x0fb00000) == 0x03200000) { arm_op_move_to_status_from_immediate(); 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()
|
||||
|
||||
if((instruction() & 0x0e000010) == 0x00000000) { arm_op_data_immediate_shift(); return; }
|
||||
if((instruction() & 0x0e000090) == 0x00000010) { arm_op_data_register_shift(); return; }
|
||||
if((instruction() & 0x0e000000) == 0x02000000) { arm_op_data_immediate(); return; }
|
||||
if((instruction() & 0x0e000000) == 0x04000000) { arm_op_move_immediate_offset(); return; }
|
||||
if((instruction() & 0x0e000010) == 0x06000000) { arm_op_move_register_offset(); return; }
|
||||
if((instruction() & 0x0e000000) == 0x08000000) { arm_op_move_multiple(); return; }
|
||||
if((instruction() & 0x0e000000) == 0x0a000000) { arm_op_branch(); return; }
|
||||
if((instruction() & 0x0f000000) == 0x0f000000) { arm_op_software_interrupt(); return; }
|
||||
decode("???? 0000 00?? ???? ???? ???? 1001 ????", multiply);
|
||||
decode("???? 0001 0?00 ???? ???? ---- 1001 ????", memory_swap);
|
||||
decode("???? 000? ?0?? ???? ???? ---- 1011 ????", move_half_register);
|
||||
decode("???? 000? ?1?? ???? ???? ???? 1011 ????", move_half_immediate);
|
||||
decode("???? 000? ?0?1 ???? ???? ---- 11?1 ????", load_register);
|
||||
decode("???? 000? ?1?1 ???? ???? ???? 11?1 ????", load_immediate);
|
||||
|
||||
decode("???? 0001 0?00 ++++ ???? ---- 0000 ----", move_to_register_from_status);
|
||||
decode("???? 0001 0?10 ???? ++++ ---- 0000 ????", move_to_status_from_register);
|
||||
decode("???? 0001 0010 ++++ ++++ ++++ 0001 ????", branch_exchange_register);
|
||||
|
||||
decode("???? 000? ???? ???? ???? ???? ???0 ????", data_immediate_shift);
|
||||
decode("???? 000? ???? ???? ???? ???? 0??1 ????", data_register_shift);
|
||||
decode("???? 001? ???? ???? ???? ???? ???? ????", data_immediate);
|
||||
decode("???? 0011 0?10 ???? ++++ ???? ???? ????", move_to_status_from_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
|
||||
|
||||
exception = true;
|
||||
}
|
||||
|
||||
bool ARM::arm_condition() {
|
||||
uint4 condition = instruction() >> 28;
|
||||
|
||||
switch(condition) {
|
||||
case 0: return cpsr().z == 1; //EQ (equal)
|
||||
case 1: return cpsr().z == 0; //NE (not equal)
|
||||
case 2: return cpsr().c == 1; //CS (carry set)
|
||||
case 3: return cpsr().c == 0; //CC (carry clear)
|
||||
case 4: return cpsr().n == 1; //MI (negative)
|
||||
case 5: return cpsr().n == 0; //PL (positive)
|
||||
case 6: return cpsr().v == 1; //VS (overflow)
|
||||
case 7: return cpsr().v == 0; //VC (no overflow)
|
||||
case 8: return cpsr().c == 1 && cpsr().z == 0; //HI (unsigned higher)
|
||||
case 9: return cpsr().c == 0 || cpsr().z == 1; //LS (unsigned lower or same)
|
||||
case 10: return cpsr().n == cpsr().v; //GE (signed greater than or equal)
|
||||
case 11: return cpsr().n != cpsr().v; //LT (signed less than)
|
||||
case 12: return cpsr().z == 0 && cpsr().n == cpsr().v; //GT (signed greater than)
|
||||
case 13: return cpsr().z == 1 || cpsr().n != cpsr().v; //LE (signed less than or equal)
|
||||
case 14: return true; //AL (always)
|
||||
case 15: return false; //NV (never)
|
||||
}
|
||||
}
|
||||
|
||||
void ARM::arm_opcode(uint32 rm) {
|
||||
uint4 opcode = instruction() >> 21;
|
||||
uint1 save = instruction() >> 20;
|
||||
|
@ -235,23 +227,6 @@ void ARM::arm_op_multiply() {
|
|||
}
|
||||
}
|
||||
|
||||
//mrs{condition} rd,(c,s)psr
|
||||
//cccc 0001 0r00 ++++ dddd ---- 0000 ----
|
||||
//c = condition
|
||||
//r = SPSR (0 = CPSR)
|
||||
//d = rd
|
||||
void ARM::arm_op_move_to_register_from_status() {
|
||||
uint1 source = instruction() >> 22;
|
||||
uint4 d = instruction() >> 12;
|
||||
|
||||
if(source) {
|
||||
if(mode() == Processor::Mode::USR) return;
|
||||
if(mode() == Processor::Mode::SYS) return;
|
||||
}
|
||||
|
||||
r(d) = source ? spsr() : cpsr();
|
||||
}
|
||||
|
||||
//swp{condition}{b} rd,rm,[rn]
|
||||
//cccc 0001 0b00 nnnn dddd ---- 1001 mmmm
|
||||
//c = condition
|
||||
|
@ -270,6 +245,151 @@ void ARM::arm_op_memory_swap() {
|
|||
r(d) = word;
|
||||
}
|
||||
|
||||
//(ldr,str){condition}h rd,[rn,rm]{!}
|
||||
//(ldr,str){condition}h rd,[rn],rm
|
||||
//cccc 000p u0wl nnnn dddd ---- 1011 mmmm
|
||||
//c = condition
|
||||
//p = pre (0 = post)
|
||||
//u = up
|
||||
//w = writeback
|
||||
//l = load (0 = save)
|
||||
//n = rn
|
||||
//d = rd
|
||||
//m = rm
|
||||
void ARM::arm_op_move_half_register() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 writeback = instruction() >> 21;
|
||||
uint1 load = instruction() >> 20;
|
||||
uint4 n = instruction() >> 16;
|
||||
uint4 d = instruction() >> 12;
|
||||
uint4 m = instruction();
|
||||
|
||||
uint32 rn = r(n);
|
||||
uint32 rm = r(m);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(load == 1) r(d) = bus_read(rn, Word);
|
||||
if(load == 0) bus_write(rn, Word, r(d));
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||
}
|
||||
|
||||
//(ldr,str){condition}h rd,[rn{,+/-offset}]{!}
|
||||
//(ldr,str){condition}h rd,[rn]{,+/-offset}
|
||||
//cccc 000p u1wl nnnn dddd iiii 1011 iiii
|
||||
//c = condition
|
||||
//p = pre (0 = post)
|
||||
//u = up
|
||||
//w = writeback
|
||||
//l = load (0 = save)
|
||||
//n = rn
|
||||
//d = rd
|
||||
//i = immediate hi
|
||||
//i = immediate lo
|
||||
void ARM::arm_op_move_half_immediate() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 writeback = instruction() >> 21;
|
||||
uint1 load = instruction() >> 20;
|
||||
uint4 n = instruction() >> 16;
|
||||
uint4 d = instruction() >> 12;
|
||||
uint4 ih = instruction() >> 8;
|
||||
uint4 il = instruction();
|
||||
|
||||
uint32 rn = r(n);
|
||||
uint8 immediate = (ih << 4) + (il << 0);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
if(load == 1) r(d) = bus_read(rn, Word);
|
||||
if(load == 0) bus_write(rn, Word, r(d));
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||
}
|
||||
|
||||
//ldr{condition}s(h,b) rd,[rn,rm]{!}
|
||||
//ldr{condition}s(h,b) rd,[rn],rm
|
||||
//cccc 000p u0w1 nnnn dddd ---- 11h1 mmmm
|
||||
//c = condition
|
||||
//p = pre (0 = post)
|
||||
//u = up
|
||||
//w = writeback
|
||||
//n = rn
|
||||
//d = rd
|
||||
//h = half (0 = byte)
|
||||
//m = rm
|
||||
void ARM::arm_op_load_register() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 writeback = instruction() >> 21;
|
||||
uint4 n = instruction() >> 16;
|
||||
uint4 d = instruction() >> 12;
|
||||
uint1 half = instruction() >> 5;
|
||||
uint4 m = instruction();
|
||||
|
||||
uint32 rn = r(n);
|
||||
uint32 rm = r(m);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
uint32 word = bus_read(rn, half ? Half : Byte);
|
||||
r(d) = half ? (int16)word : (int8)word;
|
||||
if(pre == 0) rm = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||
}
|
||||
|
||||
//ldr{condition}s(h,b) rd,[rn{,+/-offset}]{!}
|
||||
//ldr{condition}s(h,b) rd,[rn]{,+/-offset}
|
||||
//cccc 000p u1w1 nnnn dddd iiii 11h1 iiii
|
||||
//c = condition
|
||||
//p = pre (0 = post)
|
||||
//u = up
|
||||
//w = writeback
|
||||
//n = rn
|
||||
//d = rd
|
||||
//i = immediate hi
|
||||
//h = half (0 = byte)
|
||||
//i = immediate lo
|
||||
void ARM::arm_op_load_immediate() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 writeback = instruction() >> 21;
|
||||
uint4 n = instruction() >> 16;
|
||||
uint4 d = instruction() >> 12;
|
||||
uint4 ih = instruction() >> 8;
|
||||
uint1 half = instruction() >> 5;
|
||||
uint4 il = instruction();
|
||||
|
||||
uint32 rn = r(n);
|
||||
uint8 immediate = (ih << 4) + (il << 0);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
uint32 word = bus_read(rn, half ? Half : Byte);
|
||||
r(d) = half ? (int16)word : (int8)word;
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||
}
|
||||
|
||||
//mrs{condition} rd,(c,s)psr
|
||||
//cccc 0001 0r00 ++++ dddd ---- 0000 ----
|
||||
//c = condition
|
||||
//r = SPSR (0 = CPSR)
|
||||
//d = rd
|
||||
void ARM::arm_op_move_to_register_from_status() {
|
||||
uint1 source = instruction() >> 22;
|
||||
uint4 d = instruction() >> 12;
|
||||
|
||||
if(source) {
|
||||
if(mode() == Processor::Mode::USR) return;
|
||||
if(mode() == Processor::Mode::SYS) return;
|
||||
}
|
||||
|
||||
r(d) = source ? spsr() : cpsr();
|
||||
}
|
||||
|
||||
//msr{condition} (c,s)psr:{fields},rm
|
||||
//cccc 0001 0r10 ffff ++++ ---- 0000 mmmm
|
||||
//c = condition
|
||||
|
@ -432,7 +552,7 @@ void ARM::arm_op_move_immediate_offset() {
|
|||
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||
}
|
||||
|
||||
//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{1}
|
||||
//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{!}
|
||||
//(ldr,str){condition}{b} rd,[rn],rm {mode} #immediate
|
||||
//cccc 011p ubwl nnnn dddd llll lss0 mmmm
|
||||
//c = condition
|
||||
|
|
|
@ -11,10 +11,16 @@ void ror(bool &c, uint32 &rm, uint32 rs);
|
|||
void rrx(bool &c, uint32 &rm);
|
||||
|
||||
void arm_op_multiply();
|
||||
void arm_op_move_to_register_from_status();
|
||||
void arm_op_memory_swap();
|
||||
void arm_op_move_half_register();
|
||||
void arm_op_move_half_immediate();
|
||||
void arm_op_load_register();
|
||||
void arm_op_load_immediate();
|
||||
|
||||
void arm_op_move_to_register_from_status();
|
||||
void arm_op_move_to_status_from_register();
|
||||
void arm_op_branch_exchange_register();
|
||||
|
||||
void arm_op_move_to_status_from_immediate();
|
||||
void arm_op_data_immediate_shift();
|
||||
void arm_op_data_register_shift();
|
||||
|
|
|
@ -21,54 +21,45 @@ void ARM::thumb_step() {
|
|||
pipeline.fetch.instruction = bus_read(r(15), Half);
|
||||
step(1);
|
||||
|
||||
//print(disassemble_registers(), "\n");
|
||||
//print(disassemble_thumb_instruction(pipeline.execute.address), "\n");
|
||||
instructions++;
|
||||
if(trace) {
|
||||
print(disassemble_registers(), "\n");
|
||||
print(disassemble_thumb_instruction(pipeline.execute.address), "\n");
|
||||
}
|
||||
|
||||
if((instruction() & 0xfc00) == 0x1800) { thumb_op_adjust_register(); return; }
|
||||
if((instruction() & 0xfc00) == 0x1c00) { thumb_op_adjust_immediate(); return; }
|
||||
if((instruction() & 0xe000) == 0x0000) { thumb_op_shift_immediate(); return; }
|
||||
if((instruction() & 0xe000) == 0x2000) { thumb_op_immediate(); return; }
|
||||
if((instruction() & 0xfc00) == 0x4000) { thumb_op_alu(); return; }
|
||||
if((instruction() & 0xff80) == 0x4700) { thumb_op_branch_exchange(); return; }
|
||||
if((instruction() & 0xfc00) == 0x4400) { thumb_op_alu_hi(); return; }
|
||||
if((instruction() & 0xf800) == 0x4800) { thumb_op_load_literal(); return; }
|
||||
if((instruction() & 0xf000) == 0x5000) { thumb_op_move_register_offset(); return; }
|
||||
if((instruction() & 0xf000) == 0x6000) { thumb_op_move_word_immediate(); return; }
|
||||
if((instruction() & 0xf000) == 0x7000) { thumb_op_move_byte_immediate(); return; }
|
||||
if((instruction() & 0xf000) == 0x8000) { thumb_op_move_half_immediate(); return; }
|
||||
if((instruction() & 0xf000) == 0x9000) { thumb_op_move_stack(); return; }
|
||||
if((instruction() & 0xf000) == 0xa000) { thumb_op_add_register_hi(); return; }
|
||||
if((instruction() & 0xff00) == 0xb000) { thumb_op_adjust_stack(); return; }
|
||||
if((instruction() & 0xf600) == 0xb400) { thumb_op_stack_multiple(); return; }
|
||||
if((instruction() & 0xf000) == 0xc000) { thumb_op_move_multiple(); return; }
|
||||
if((instruction() & 0xff00) == 0xdf00) { thumb_op_software_interrupt(); return; }
|
||||
if((instruction() & 0xf000) == 0xd000) { thumb_op_branch_conditional(); return; }
|
||||
if((instruction() & 0xf800) == 0xe000) { thumb_op_branch_short(); return; }
|
||||
if((instruction() & 0xf800) == 0xf000) { thumb_op_branch_long_prefix(); return; }
|
||||
if((instruction() & 0xf800) == 0xf800) { thumb_op_branch_long_suffix(); return; }
|
||||
#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
|
||||
|
||||
exception = true;
|
||||
}
|
||||
|
||||
bool ARM::thumb_condition(uint4 condition) {
|
||||
switch(condition) {
|
||||
case 0: return cpsr().z == 1; //EQ (equal)
|
||||
case 1: return cpsr().z == 0; //NE (not equal)
|
||||
case 2: return cpsr().c == 1; //CS (carry set)
|
||||
case 3: return cpsr().c == 0; //CC (carry clear)
|
||||
case 4: return cpsr().n == 1; //MI (negative)
|
||||
case 5: return cpsr().n == 0; //PL (positive)
|
||||
case 6: return cpsr().v == 1; //VS (overflow)
|
||||
case 7: return cpsr().v == 0; //VC (no overflow)
|
||||
case 8: return cpsr().c == 1 && cpsr().z == 0; //HI (unsigned higher)
|
||||
case 9: return cpsr().c == 0 || cpsr().z == 1; //LS (unsigned lower or same)
|
||||
case 10: return cpsr().n == cpsr().v; //GE (signed greater than or equal)
|
||||
case 11: return cpsr().n != cpsr().v; //LT (signed less than)
|
||||
case 12: return cpsr().z == 0 && cpsr().n == cpsr().v; //GT (signed greater than)
|
||||
case 13: return cpsr().z == 1 || cpsr().n != cpsr().v; //LE (signed less than or equal)
|
||||
}
|
||||
}
|
||||
|
||||
void ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) {
|
||||
switch(opcode) {
|
||||
case 0: r(d) = thumb_tst(r(d) & r(m)); break; //AND
|
||||
|
@ -381,8 +372,8 @@ void ARM::thumb_op_add_register_hi() {
|
|||
uint3 d = instruction() >> 8;
|
||||
uint8 immediate = instruction();
|
||||
|
||||
if(sp == 0) r(d) = (r(15) & ~2) + immediate;
|
||||
if(sp == 1) r(d) = r(13) + immediate;
|
||||
if(sp == 0) r(d) = (r(15) & ~2) + immediate * 4;
|
||||
if(sp == 1) r(d) = r(13) + immediate * 4;
|
||||
}
|
||||
|
||||
//(add,sub) sp,#immediate
|
||||
|
@ -464,10 +455,10 @@ void ARM::thumb_op_software_interrupt() {
|
|||
//c = condition
|
||||
//d = displacement
|
||||
void ARM::thumb_op_branch_conditional() {
|
||||
uint4 condition = instruction() >> 8;
|
||||
uint4 flagcondition = instruction() >> 8;
|
||||
int8 displacement = instruction();
|
||||
|
||||
if(thumb_condition(condition) == false) return;
|
||||
if(condition(flagcondition) == false) return;
|
||||
r(15) = r(15) + displacement * 2;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,9 @@ void ArmDSP::enter() {
|
|||
}
|
||||
|
||||
if(exception) {
|
||||
print("* ARM unknown instruction\n");
|
||||
print(disassemble_arm_instruction(pipeline.execute.address), "\n");
|
||||
print(disassemble_registers(), "\n");
|
||||
print("Executed: ", instructions, "\n");
|
||||
while(true) step(frequency);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue