mirror of https://github.com/bsnes-emu/bsnes.git
Update to v087r05 release.
byuu says: Implemented all of the ARMv3 instructions, and the bx rm instruction as well. Already hit THUMB mode right at the start of the BIOS, sigh. Implemented the first THUMB instruction to get that rolling. Also tried to support the S flag to LDM/STM, but not sure how successful I was.
This commit is contained in:
parent
6701403745
commit
04087a74b0
|
@ -93,6 +93,7 @@ sync:
|
|||
rm -r phoenix/test
|
||||
|
||||
archive-all:
|
||||
tar -cjf bsnes.tar.bz2 base data gb gba libco nall nes obj out phoenix ruby snes target-debugger target-libsnes target-ui Makefile cc.bat purge.bat
|
||||
if [ -f bsnes.tar.bz2 ]; then rm bsnes.tar.bz2; fi
|
||||
tar -cjf bsnes.tar.bz2 `ls`
|
||||
|
||||
help:;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef BASE_HPP
|
||||
#define BASE_HPP
|
||||
|
||||
const char Version[] = "087.04";
|
||||
static const char Version[] = "087.05";
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
|
|
|
@ -0,0 +1,490 @@
|
|||
void ARM::arm_step() {
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Word);
|
||||
|
||||
r(15).data += 4;
|
||||
pipeline.decode = pipeline.fetch;
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Word);
|
||||
step(2);
|
||||
}
|
||||
|
||||
r(15).data += 4;
|
||||
pipeline.execute = pipeline.decode;
|
||||
pipeline.decode = pipeline.fetch;
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Word);
|
||||
step(2);
|
||||
|
||||
print(disassemble_arm_opcode(pipeline.execute.address), "\n");
|
||||
|
||||
if(arm_condition() == 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) == 0x01200000) { arm_op_move_to_status_from_register(); return; }
|
||||
if((instruction() & 0x0ff000f0) == 0x01200010) { arm_op_branch_exchange_register(); return; }
|
||||
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; }
|
||||
|
||||
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;
|
||||
uint4 n = instruction() >> 16;
|
||||
uint4 d = instruction() >> 12;
|
||||
|
||||
uint32 rn = r(n);
|
||||
|
||||
auto test = [&](uint32 result) {
|
||||
if(save) {
|
||||
cpsr().n = result >> 31;
|
||||
cpsr().z = result == 0;
|
||||
cpsr().c = carryout();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto math = [&](uint32 source, uint32 modify, bool carry) {
|
||||
uint32 result = source + modify + carry;
|
||||
if(save) {
|
||||
uint32 overflow = ~(source ^ modify) & (source ^ result);
|
||||
cpsr().n = result >> 31;
|
||||
cpsr().z = result == 0;
|
||||
cpsr().c = (1u << 31) & (overflow ^ source ^ modify ^ result);
|
||||
cpsr().v = (1u << 31) & (overflow);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
switch(opcode) {
|
||||
case 0: r(d) = test(rn & rm); break; //AND
|
||||
case 1: r(d) = test(rn ^ rm); break; //EOR
|
||||
case 2: r(d) = math(rn, ~rm, 1); break; //SUB
|
||||
case 3: r(d) = math(rm, ~rn, 1); break; //RSB
|
||||
case 4: r(d) = math(rn, rm, 0); break; //ADD
|
||||
case 5: r(d) = math(rn, rm, cpsr().c); break; //ADC
|
||||
case 6: r(d) = math(rn, ~rm, cpsr().c); break; //SBC
|
||||
case 7: r(d) = math(rm, ~rn, cpsr().c); break; //RSC
|
||||
case 8: test(rn & rm); break; //TST
|
||||
case 9: test(rn ^ rm); break; //TEQ
|
||||
case 10: math(rn, ~rm, 1); break; //CMP
|
||||
case 11: math(rn, rm, 0); break; //CMN
|
||||
case 12: r(d) = test(rn | rm); break; //ORR
|
||||
case 13: r(d) = test(rm); break; //MOV
|
||||
case 14: r(d) = test(rn &~rm); break; //BIC
|
||||
case 15: r(d) = test(~rm); break; //MVN
|
||||
}
|
||||
}
|
||||
|
||||
//logical shift left
|
||||
void ARM::lsl(bool &c, uint32 &rm, uint32 rs) {
|
||||
while(rs--) {
|
||||
c = rm >> 31;
|
||||
rm <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//logical shift right
|
||||
void ARM::lsr(bool &c, uint32 &rm, uint32 rs) {
|
||||
while(rs--) {
|
||||
c = rm & 1;
|
||||
rm >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
//arithmetic shift right
|
||||
void ARM::asr(bool &c, uint32 &rm, uint32 rs) {
|
||||
while(rs--) {
|
||||
c = rm & 1;
|
||||
rm = (int32)rm >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
//rotate right
|
||||
void ARM::ror(bool &c, uint32 &rm, uint32 rs) {
|
||||
while(rs--) {
|
||||
c = rm & 1;
|
||||
rm = (rm << 31) | (rm >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
//rotate right with extend
|
||||
void ARM::rrx(bool &c, uint32 &rm) {
|
||||
bool carry = c;
|
||||
c = rm & 1;
|
||||
rm = (carry << 31) | (rm >> 1);
|
||||
}
|
||||
|
||||
//mul{condition}{s} rd,rm,rs
|
||||
//mla{condition}{s} rd,rm,rs,rn
|
||||
//cccc 0000 00as dddd nnnn ssss 1001 mmmm
|
||||
//c = condition
|
||||
//a = accumulate
|
||||
//s = save flags
|
||||
//d = rd
|
||||
//n = rn
|
||||
//s = rs
|
||||
//n = rm
|
||||
void ARM::arm_op_multiply() {
|
||||
uint1 accumulate = instruction() >> 21;
|
||||
uint1 save = instruction() >> 20;
|
||||
uint4 d = instruction() >> 16;
|
||||
uint4 n = instruction() >> 12;
|
||||
uint4 s = instruction() >> 8;
|
||||
uint4 m = instruction() >> 0;
|
||||
|
||||
//Booth's algorithm: two bit steps
|
||||
uint32 temp = r(s);
|
||||
while(temp) {
|
||||
temp >>= 2;
|
||||
step(1);
|
||||
}
|
||||
r(d) = r(m) * r(s);
|
||||
|
||||
if(accumulate) {
|
||||
step(1);
|
||||
r(d) += r(n);
|
||||
}
|
||||
|
||||
if(save) {
|
||||
cpsr().n = r(d) >> 31;
|
||||
cpsr().z = r(d) == 0;
|
||||
cpsr().c = 0; //undefined
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
//r = SPSR (0 = CPSR)
|
||||
//f = field mask
|
||||
//m = rm
|
||||
void ARM::arm_op_move_to_status_from_register() {
|
||||
uint1 source = instruction() >> 22;
|
||||
uint4 field = instruction() >> 16;
|
||||
uint4 m = instruction();
|
||||
|
||||
if(source) {
|
||||
if(mode() == Processor::Mode::USR) return;
|
||||
if(mode() == Processor::Mode::SYS) return;
|
||||
}
|
||||
|
||||
PSR &psr = source ? spsr() : cpsr();
|
||||
uint32 rm = r(m);
|
||||
|
||||
if(field & 1) {
|
||||
psr.i = rm & 0x00000080;
|
||||
psr.f = rm & 0x00000040;
|
||||
psr.t = rm & 0x00000020;
|
||||
psr.m = rm & 0x0000001f;
|
||||
|
||||
if(source == 0) {
|
||||
processor.setMode((Processor::Mode)psr.m);
|
||||
}
|
||||
}
|
||||
|
||||
if(field & 8) {
|
||||
psr.n = rm & 0x80000000;
|
||||
psr.z = rm & 0x40000000;
|
||||
psr.c = rm & 0x20000000;
|
||||
psr.v = rm & 0x10000000;
|
||||
}
|
||||
}
|
||||
|
||||
//bx{condition} rm
|
||||
//cccc 0001 0010 ++++ ++++ ++++ 0001 mmmm
|
||||
//c = condition
|
||||
//m = rm
|
||||
void ARM::arm_op_branch_exchange_register() {
|
||||
uint4 m = instruction();
|
||||
|
||||
r(15) = r(m);
|
||||
cpsr().t = r(m) & 1;
|
||||
}
|
||||
|
||||
//{opcode}{condition}{s} rd,rm {shift} #immediate
|
||||
//{opcode}{condition} rn,rm {shift} #immediate
|
||||
//{opcode}{condition}{s} rd,rn,rm {shift} #immediate
|
||||
//cccc 000o ooos nnnn dddd llll lss0 mmmm
|
||||
//c = condition
|
||||
//o = opcode
|
||||
//s = save flags
|
||||
//n = rn
|
||||
//d = rd
|
||||
//l = shift immediate
|
||||
//s = shift
|
||||
//m = rm
|
||||
void ARM::arm_op_data_immediate_shift() {
|
||||
uint1 save = instruction() >> 20;
|
||||
uint5 shift = instruction() >> 7;
|
||||
uint2 mode = instruction() >> 5;
|
||||
uint4 m = instruction();
|
||||
|
||||
uint32 rs = shift;
|
||||
uint32 rm = r(m);
|
||||
bool c = cpsr().c;
|
||||
|
||||
if(mode == 0) lsl(c, rm, rs);
|
||||
if(mode == 1) lsr(c, rm, rs ? rs : 32);
|
||||
if(mode == 2) asr(c, rm, rs ? rs : 32);
|
||||
if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm);
|
||||
|
||||
carryout() = c;
|
||||
arm_opcode(rm);
|
||||
}
|
||||
|
||||
//{opcode}{condition}{s} rd,rm {shift} rs
|
||||
//{opcode}{condition} rn,rm {shift} rs
|
||||
//{opcode}{condition}{s} rd,rn,rm {shift} rs
|
||||
//cccc 000o ooos nnnn dddd ssss 0ss1 mmmm
|
||||
//c = condition
|
||||
//o = opcode
|
||||
//s = save flags
|
||||
//n = rn
|
||||
//d = rd
|
||||
//s = rs
|
||||
//s = shift
|
||||
//m = rm
|
||||
void ARM::arm_op_data_register_shift() {
|
||||
uint1 save = instruction() >> 20;
|
||||
uint4 s = instruction() >> 8;
|
||||
uint2 mode = instruction() >> 5;
|
||||
uint4 m = instruction();
|
||||
|
||||
uint8 rs = r(s);
|
||||
uint32 rm = r(m);
|
||||
bool c = cpsr().c;
|
||||
|
||||
if(mode == 0) lsl(c, rm, rs < 33 ? rs : 33);
|
||||
if(mode == 1) lsr(c, rm, rs < 33 ? rs : 33);
|
||||
if(mode == 2) asr(c, rm, rs < 32 ? rs : 32);
|
||||
if(mode == 3 && rs) ror(c, rm, rs & 31 == 0 ? 32 : rs & 31);
|
||||
|
||||
carryout() = c;
|
||||
arm_opcode(rm);
|
||||
}
|
||||
|
||||
//{opcode}{condition}{s} rd,#immediate
|
||||
//{opcode}{condition} rn,#immediate
|
||||
//{opcode}{condition}{s} rd,rn,#immediate
|
||||
//cccc 001o ooos nnnn dddd ssss iiii iiii
|
||||
//c = condition
|
||||
//o = opcode
|
||||
//s = save flags
|
||||
//n = rn
|
||||
//d = rd
|
||||
//s = shift immediate
|
||||
//i = immediate
|
||||
void ARM::arm_op_data_immediate() {
|
||||
uint1 save = instruction() >> 20;
|
||||
uint4 shift = instruction() >> 8;
|
||||
uint8 immediate = instruction();
|
||||
|
||||
uint32 rs = shift << 1;
|
||||
uint32 rm = (immediate >> rs) | (immediate << (32 - rs));
|
||||
if(rs) carryout() = immediate >> 31;
|
||||
|
||||
arm_opcode(rm);
|
||||
}
|
||||
|
||||
//(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!}
|
||||
//(ldr,str){condition}{b} rd,[rn]{,+/-offset}
|
||||
//cccc 010p ubwl nnnn dddd iiii iiii iiii
|
||||
//c = condition
|
||||
//p = pre (0 = post-indexed addressing)
|
||||
//u = up (add/sub offset to base)
|
||||
//b = byte (1 = word)
|
||||
//w = writeback
|
||||
//l = load (0 = save)
|
||||
//n = rn
|
||||
//d = rd
|
||||
//i = immediate
|
||||
void ARM::arm_op_move_immediate_offset() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 byte = instruction() >> 22;
|
||||
uint1 writeback = instruction() >> 21;
|
||||
uint1 load = instruction() >> 20;
|
||||
uint4 n = instruction() >> 16;
|
||||
uint4 d = instruction() >> 12;
|
||||
uint12 rm = instruction();
|
||||
|
||||
uint32 rn = r(n);
|
||||
auto &rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(load) {
|
||||
rd = bus.read(rn, byte ? Byte : Word);
|
||||
} else {
|
||||
bus.write(rn, byte ? Byte : Word, rd);
|
||||
}
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
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
|
||||
//cccc 011p ubwl nnnn dddd llll lss0 mmmm
|
||||
//c = condition
|
||||
//p = pre (0 = post-indexed addressing)
|
||||
//u = up
|
||||
//b = byte (1 = word)
|
||||
//w = writeback
|
||||
//l = load (0 = save)
|
||||
//n = rn
|
||||
//d = rd
|
||||
//l = shift immediate
|
||||
//s = shift mode
|
||||
//m = rm
|
||||
void ARM::arm_op_move_register_offset() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 byte = instruction() >> 22;
|
||||
uint1 writeback = instruction() >> 21;
|
||||
uint1 load = instruction() >> 20;
|
||||
uint4 n = instruction() >> 16;
|
||||
uint4 d = instruction() >> 12;
|
||||
uint5 immediate = instruction() >> 7;
|
||||
uint2 mode = instruction() >> 5;
|
||||
uint4 m = instruction();
|
||||
|
||||
uint32 rn = r(n);
|
||||
auto &rd = r(d);
|
||||
uint32 rs = immediate;
|
||||
uint32 rm = r(m);
|
||||
bool c = cpsr().c;
|
||||
|
||||
if(mode == 0) lsl(c, rm, rs);
|
||||
if(mode == 1) lsr(c, rm, rs ? rs : 32);
|
||||
if(mode == 2) asr(c, rm, rs ? rs : 32);
|
||||
if(mode == 3) rs ? ror(c, rm, rs) : rrx(c, rm);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(load) {
|
||||
rd = bus.read(rn, byte ? Byte : Word);
|
||||
} else {
|
||||
bus.write(rn, byte ? Byte : Word, rd);
|
||||
}
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||
}
|
||||
|
||||
//(ldm,stm){condition}{mode} rn{!},{r...}
|
||||
//cccc 100p uswl nnnn llll llll llll llll
|
||||
//c = condition
|
||||
//p = pre (0 = post-indexed addressing)
|
||||
//u = up (add/sub offset to base)
|
||||
//s = spsr copy -or- usr register copy
|
||||
//w = writeback
|
||||
//l = load (0 = save)
|
||||
//n = rn
|
||||
//l = register list
|
||||
void ARM::arm_op_move_multiple() {
|
||||
uint1 pre = instruction() >> 24;
|
||||
uint1 up = instruction() >> 23;
|
||||
uint1 s = instruction() >> 22;
|
||||
uint1 writeback = instruction() >> 21;
|
||||
uint1 load = instruction() >> 20;
|
||||
uint4 n = instruction() >> 16;
|
||||
uint16 list = instruction();
|
||||
|
||||
uint32 rn = r(n);
|
||||
if(pre == 0 && up == 1) rn = rn + 0; //IA
|
||||
if(pre == 1 && up == 1) rn = rn + 4; //IB
|
||||
if(pre == 1 && up == 0) rn = rn - bit::count(list) * 4 + 0; //DB
|
||||
if(pre == 0 && up == 0) rn = rn - bit::count(list) * 4 + 4; //DA
|
||||
|
||||
Processor::Mode pmode = mode();
|
||||
bool usr = false;
|
||||
if(s && load == 1 && (list & 0x8000) == 0) usr = true;
|
||||
if(s && load == 0) usr = true;
|
||||
|
||||
if(usr) processor.setMode(Processor::Mode::USR);
|
||||
|
||||
for(unsigned n = 0; n < 16; n++) {
|
||||
if(list & (1 << n)) {
|
||||
if(load) r(n) = bus.read(rn, Word);
|
||||
else bus.write(rn, Word, r(n));
|
||||
rn += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if(usr) processor.setMode(pmode);
|
||||
|
||||
if(load == 1 && s && (list & 0x8000)) {
|
||||
if(mode() != Processor::Mode::USR && mode() != Processor::Mode::SYS) {
|
||||
cpsr() = spsr();
|
||||
processor.setMode((Processor::Mode)cpsr().m);
|
||||
}
|
||||
}
|
||||
|
||||
if(writeback) {
|
||||
if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA, IB
|
||||
if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA, DB
|
||||
}
|
||||
}
|
||||
|
||||
//b{l}{condition} address
|
||||
//cccc 101l dddd dddd dddd dddd dddd dddd
|
||||
//c = condition
|
||||
//l = link
|
||||
//d = displacement (24-bit signed)
|
||||
void ARM::arm_op_branch() {
|
||||
uint1 link = instruction() >> 24;
|
||||
int24 displacement = instruction();
|
||||
|
||||
if(link) r(14) = r(15) - 4;
|
||||
r(15) += displacement * 4;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
void arm_step();
|
||||
|
||||
bool arm_condition();
|
||||
void arm_opcode(uint32 rm);
|
||||
|
||||
void lsl(bool &c, uint32 &rm, uint32 rs);
|
||||
void lsr(bool &c, uint32 &rm, uint32 rs);
|
||||
void asr(bool &c, uint32 &rm, uint32 rs);
|
||||
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_move_to_status_from_register();
|
||||
void arm_op_branch_exchange_register();
|
||||
void arm_op_data_immediate_shift();
|
||||
void arm_op_data_register_shift();
|
||||
void arm_op_data_immediate();
|
||||
void arm_op_move_immediate_offset();
|
||||
void arm_op_move_register_offset();
|
||||
void arm_op_move_multiple();
|
||||
void arm_op_branch();
|
|
@ -1,8 +1,14 @@
|
|||
#include "registers.cpp"
|
||||
#include "arm.cpp"
|
||||
#include "thumb.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
void ARM::power() {
|
||||
processor.power();
|
||||
pipeline.reload = true;
|
||||
exception = false;
|
||||
r(15).modify = [&] { pipeline.reload = true; };
|
||||
r(15).modify = [&] {
|
||||
pipeline.reload = true;
|
||||
r(15).data &= cpsr().t ? ~1 : ~3;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
struct ARM {
|
||||
#include "registers.hpp"
|
||||
#include "arm.hpp"
|
||||
#include "thumb.hpp"
|
||||
#include "disassembler.hpp"
|
||||
virtual void step(unsigned clocks) = 0;
|
||||
|
||||
void power();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,314 @@
|
|||
string ARM::disassemble_arm_opcode(uint32 pc) {
|
||||
static string conditions[] = {
|
||||
"eq", "ne", "cs", "cc",
|
||||
"mi", "pl", "vs", "vc",
|
||||
"hi", "ls", "ge", "lt",
|
||||
"gt", "le", "", "nv",
|
||||
};
|
||||
|
||||
static string opcodes[] = {
|
||||
"and", "eor", "sub", "rsb",
|
||||
"add", "adc", "sbc", "rsc",
|
||||
"tst", "teq", "cmp", "cmn",
|
||||
"orr", "mov", "bic", "mvn",
|
||||
};
|
||||
|
||||
static string registers[] = {
|
||||
"r0", "r1", "r2", "r3",
|
||||
"r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11",
|
||||
"r12", "sp", "lr", "pc",
|
||||
};
|
||||
|
||||
static string indices[] = {
|
||||
"da", "ia", "db", "ib",
|
||||
};
|
||||
|
||||
static auto is_move = [](uint4 opcode) { return opcode == 13 || opcode == 15; };
|
||||
static auto is_comp = [](uint4 opcode) { return opcode >= 8 && opcode <= 11; };
|
||||
static auto is_math = [](uint4 opcode) { return opcode < 8 || opcode == 12 || opcode == 14; };
|
||||
|
||||
string output{hex<8>(pc), " "};
|
||||
|
||||
uint32 instruction = bus.read(pc, Word);
|
||||
output.append(hex<8>(instruction), " ");
|
||||
|
||||
//multiply()
|
||||
//mul{condition}{s} rd,rm,rs
|
||||
//mla{condition}{s} rd,rm,rs,rn
|
||||
if((instruction & 0x0fc000f0) == 0x00000090) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 accumulate = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 rd = instruction >> 16;
|
||||
uint4 rn = instruction >> 12;
|
||||
uint4 rs = instruction >> 8;
|
||||
uint4 rm = instruction >> 0;
|
||||
|
||||
output.append(accumulate ? "mla" : "mul", conditions[condition], save ? "s " : " ");
|
||||
output.append(registers[rd], ",", registers[rm], ",", registers[rs]);
|
||||
if(accumulate) output.append(",", registers[rn]);
|
||||
|
||||
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) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 psr = instruction >> 22;
|
||||
uint4 field = instruction >> 16;
|
||||
uint4 rm = instruction;
|
||||
|
||||
output.append("msr", conditions[condition], " ");
|
||||
output.append(psr ? "spsr:" : "cpsr:");
|
||||
output.append(
|
||||
field & 1 ? "c" : "",
|
||||
field & 2 ? "x" : "",
|
||||
field & 4 ? "s" : "",
|
||||
field & 8 ? "f" : ""
|
||||
);
|
||||
output.append(",", registers[rm]);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//branch_exchange_register()
|
||||
//bx{condition} rm
|
||||
if((instruction & 0x0ff000f0) == 0x01200010) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint4 rm = instruction;
|
||||
|
||||
output.append("bx", conditions[condition], " ");
|
||||
output.append(registers[rm]);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//data_immediate_shift()
|
||||
//{opcode}{condition}{s} rd,rm {shift} #immediate
|
||||
//{opcode}{condition} rn,rm {shift} #immediate
|
||||
//{opcode}{condition}{s} rd,rn,rm {shift} #immediate
|
||||
if((instruction & 0x0e000010) == 0x00000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint4 opcode = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint5 shift = instruction >> 7;
|
||||
uint2 op = instruction >> 5;
|
||||
uint4 rm = instruction;
|
||||
|
||||
output.append(opcodes[opcode], conditions[condition]);
|
||||
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd]);
|
||||
if(is_comp(opcode)) output.append(" ", registers[rn]);
|
||||
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
|
||||
output.append(",", registers[rm]);
|
||||
if(op == 0 && shift != 0) output.append(" lsl #", shift);
|
||||
if(op == 1) output.append(" lsr #", shift == 0 ? 32u : (unsigned)shift);
|
||||
if(op == 2) output.append(" asr #", shift == 0 ? 32u : (unsigned)shift);
|
||||
if(op == 3 && shift != 0) output.append(" ror #", shift);
|
||||
if(op == 3 && shift == 0) output.append(" rrx");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//data_register_shift()
|
||||
//{opcode}{condition}{s} rd,rm {shift} rs
|
||||
//{opcode}{condition} rn,rm {shift} rs
|
||||
//{opcode}{condition}{s} rd,rn,rm {shift} rs
|
||||
if((instruction & 0x0e000090) == 0x00000010) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint4 opcode = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint4 rs = instruction >> 8;
|
||||
uint2 mode = instruction >> 5;
|
||||
uint4 rm = instruction;
|
||||
|
||||
output.append(opcodes[opcode], conditions[condition]);
|
||||
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd], ",");
|
||||
if(is_comp(opcode)) output.append(registers[rn], ",");
|
||||
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn], ",");
|
||||
output.append(registers[rm]);
|
||||
if(mode == 0) output.append(" lsl ");
|
||||
if(mode == 1) output.append(" lsr ");
|
||||
if(mode == 2) output.append(" asr ");
|
||||
if(mode == 3) output.append(" ror ");
|
||||
output.append(registers[rs]);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//data_immediate()
|
||||
//{opcode}{condition}{s} rd,#immediate
|
||||
//{opcode}{condition} rn,#immediate
|
||||
//{opcode}{condition}{s} rd,rn,#immediate
|
||||
if((instruction & 0x0e000000) == 0x02000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint4 opcode = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint4 rotate = instruction >> 8;
|
||||
uint8 immediate = instruction;
|
||||
|
||||
uint32 rm = (immediate >> (rotate << 1)) | (immediate << (32 - (rotate << 1)));
|
||||
output.append(opcodes[opcode], conditions[condition]);
|
||||
if(is_move(opcode)) output.append(save ? "s " : " ", registers[rd]);
|
||||
if(is_comp(opcode)) output.append(" ", registers[rn]);
|
||||
if(is_math(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn]);
|
||||
output.append(",#0x", hex<8>(rm));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//move_immediate_offset()
|
||||
//(ldr,str){condition}{b} rd,[rn{,+/-offset}]{!}
|
||||
//(ldr,str){condition}{b} rd,[rn]{,+/-offset}
|
||||
if((instruction & 0x0e000000) == 0x04000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 pre = instruction >> 24;
|
||||
uint1 up = instruction >> 23;
|
||||
uint1 byte = instruction >> 22;
|
||||
uint1 writeback = instruction >> 21;
|
||||
uint1 load = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint12 immediate = instruction;
|
||||
|
||||
output.append(load ? "ldr" : "str", conditions[condition], byte ? "b " : " ");
|
||||
output.append(registers[rd], ",[", registers[rn]);
|
||||
if(pre == 0) output.append("]");
|
||||
if(immediate) output.append(",", up ? "+" : "-", "0x", hex<3>(immediate));
|
||||
if(pre == 1) output.append("]");
|
||||
if(pre == 0 || writeback == 1) output.append("!");
|
||||
|
||||
if(rn == 15) output.append(" =0x", hex<8>(bus.read(pc + 8 + (up ? +immediate : -immediate), byte ? Byte : Word)));
|
||||
return output;
|
||||
}
|
||||
|
||||
//move_register_offset()
|
||||
//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{1}
|
||||
//(ldr,str){condition}{b} rd,[rn],rm {mode} #immediate
|
||||
if((instruction & 0x0e000010) == 0x06000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 pre = instruction >> 24;
|
||||
uint1 up = instruction >> 23;
|
||||
uint1 byte = instruction >> 22;
|
||||
uint1 writeback = instruction >> 21;
|
||||
uint1 load = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint4 rd = instruction >> 12;
|
||||
uint5 shift = instruction >> 7;
|
||||
uint2 mode = instruction >> 5;
|
||||
uint4 rm = instruction;
|
||||
|
||||
output.append(load ? "ldr" : "str", conditions[condition], byte ? "b " : " ");
|
||||
output.append(registers[rd], ",[", registers[rn]);
|
||||
if(pre == 0) output.append("]");
|
||||
output.append(",", up ? "+" : "-", registers[rm]);
|
||||
if(mode == 0 && shift != 0) output.append(" lsl #", shift);
|
||||
if(mode == 1) output.append(" lsr #", shift == 0 ? 32u : (unsigned)shift);
|
||||
if(mode == 2) output.append(" asr #", shift == 0 ? 32u : (unsigned)shift);
|
||||
if(mode == 3 && shift != 0) output.append(" ror #", shift);
|
||||
if(mode == 3 && shift == 0) output.append(" rrx");
|
||||
if(pre == 1) output.append("]");
|
||||
if(pre == 0 || writeback == 1) output.append("!");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//move_multiple()
|
||||
//(ldm,stm) {condition}{mode} rn{!},{r...}{^}
|
||||
if((instruction & 0x0e000000) == 0x08000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint2 index = instruction >> 23;
|
||||
uint1 s = instruction >> 22;
|
||||
uint1 writeback = instruction >> 21;
|
||||
uint1 load = instruction >> 20;
|
||||
uint4 rn = instruction >> 16;
|
||||
uint16 list = instruction;
|
||||
|
||||
output.append(load ? "ldm" : "stm", conditions[condition], indices[index], " ");
|
||||
output.append(registers[rn], writeback ? "!" : "", ",{");
|
||||
for(unsigned n = 0; n < 16; n++) if(list & (1 << n)) output.append(registers[n], ",");
|
||||
output.rtrim<1>(",");
|
||||
output.append("}", s ? "^" : "");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//branch()
|
||||
//b{l}{condition} address
|
||||
if((instruction & 0x0e000000) == 0x0a000000) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint1 link = instruction >> 24;
|
||||
|
||||
output.append("b", link ? "l" : "", conditions[condition], " ");
|
||||
output.append("0x", hex<8>(pc + 8 + (int24)instruction * 4));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
output.append("???");
|
||||
return output;
|
||||
}
|
||||
|
||||
string ARM::disassemble_thumb_opcode(uint32 pc) {
|
||||
static string opcodes[] = { "mov", "cmp", "add", "sub" };
|
||||
|
||||
static string registers[] = {
|
||||
"r0", "r1", "r2", "r3",
|
||||
"r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11",
|
||||
"r12", "sp", "lr", "pc",
|
||||
};
|
||||
|
||||
string output{hex<8>(pc), " "};
|
||||
|
||||
uint16 instruction = bus.read(pc, Half);
|
||||
output.append(hex<4>(instruction), " ");
|
||||
|
||||
//immediate()
|
||||
//(mov,cmp,add,sub) (rd,rn),#immediate
|
||||
if((instruction & 0xe000) == 0x2000) {
|
||||
uint2 opcode = instruction >> 11;
|
||||
uint3 rd = instruction >> 8;
|
||||
uint8 immediate = instruction;
|
||||
|
||||
output.append(opcodes[opcode], " ", registers[rd], ",#0x", hex<2>(immediate));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
output.append("???");
|
||||
return output;
|
||||
}
|
||||
|
||||
string ARM::disassemble_registers() {
|
||||
string output;
|
||||
output.append( "r0:", hex<8>(r( 0)), " r1:", hex<8>(r( 1)), " r2:", hex<8>(r( 2)), " r3:", hex<8>(r( 3)), " ");
|
||||
output.append( "r4:", hex<8>(r( 4)), " r5:", hex<8>(r( 5)), " r6:", hex<8>(r( 6)), " r7:", hex<8>(r( 7)), " ");
|
||||
output.append("cpsr:", cpsr().n ? "N" : "n", cpsr().z ? "Z" : "z", cpsr().c ? "C" : "c", cpsr().v ? "V" : "v", "\n");
|
||||
output.append( "r8:", hex<8>(r( 8)), " r9:", hex<8>(r( 9)), " r10:", hex<8>(r(10)), " r11:", hex<8>(r(11)), " ");
|
||||
output.append("r12:", hex<8>(r(12)), " sp:", hex<8>(r(13)), " lr:", hex<8>(r(14)), " pc:", hex<8>(r(15)), " ");
|
||||
output.append("spsr:");
|
||||
if(mode() == Processor::Mode::USR || mode() == Processor::Mode::SYS) { output.append("----"); return output; }
|
||||
output.append( spsr().n ? "N" : "n", spsr().z ? "Z" : "z", spsr().c ? "C" : "c", spsr().v ? "V" : "v");
|
||||
return output;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
string disassemble_arm_opcode(uint32 pc);
|
||||
string disassemble_thumb_opcode(uint32 pc);
|
||||
string disassemble_registers();
|
|
@ -4,6 +4,7 @@ struct GPR {
|
|||
|
||||
inline operator uint32() const { return data; }
|
||||
inline GPR& operator=(uint32 n) { data = n; if(modify) modify(); return *this; }
|
||||
inline GPR& operator=(const GPR& source) { return operator=(source.data); }
|
||||
|
||||
inline GPR& operator &=(uint32 n) { return operator=(data & n); }
|
||||
inline GPR& operator |=(uint32 n) { return operator=(data | n); }
|
||||
|
@ -47,10 +48,12 @@ struct PSR {
|
|||
|
||||
struct Pipeline {
|
||||
bool reload;
|
||||
|
||||
struct Instruction {
|
||||
uint32 opcode;
|
||||
uint32 address;
|
||||
uint32 instruction;
|
||||
};
|
||||
|
||||
Instruction execute;
|
||||
Instruction decode;
|
||||
Instruction fetch;
|
||||
|
@ -100,6 +103,7 @@ struct Processor {
|
|||
|
||||
GPR pc;
|
||||
PSR cpsr;
|
||||
bool carryout;
|
||||
|
||||
GPR *r[16];
|
||||
PSR *spsr;
|
||||
|
@ -115,3 +119,6 @@ bool exception;
|
|||
alwaysinline GPR& r(unsigned n) { return *processor.r[n]; }
|
||||
alwaysinline PSR& cpsr() { return processor.cpsr; }
|
||||
alwaysinline PSR& spsr() { return *processor.spsr; }
|
||||
alwaysinline bool& carryout() { return processor.carryout; }
|
||||
alwaysinline uint32 instruction() { return pipeline.execute.instruction; }
|
||||
alwaysinline Processor::Mode mode() { return (Processor::Mode)processor.cpsr.m; }
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
void ARM::thumb_step() {
|
||||
if(pipeline.reload) {
|
||||
pipeline.reload = false;
|
||||
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Half);
|
||||
|
||||
r(15).data += 2;
|
||||
pipeline.decode = pipeline.fetch;
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Half);
|
||||
step(1);
|
||||
}
|
||||
|
||||
r(15).data += 2;
|
||||
pipeline.execute = pipeline.decode;
|
||||
pipeline.decode = pipeline.fetch;
|
||||
pipeline.fetch.address = r(15);
|
||||
pipeline.fetch.instruction = bus.read(r(15), Half);
|
||||
step(1);
|
||||
|
||||
print(disassemble_thumb_opcode(pipeline.execute.address), "\n");
|
||||
|
||||
if((instruction() & 0xe000) == 0x2000) { thumb_op_immediate(); return; }
|
||||
|
||||
exception = true;
|
||||
}
|
||||
|
||||
void ARM::thumb_mov(GPR &source, uint32 modify) {
|
||||
cpsr().n = modify >> 31;
|
||||
cpsr().z = modify == 0;
|
||||
source = modify;
|
||||
}
|
||||
|
||||
void ARM::thumb_cmp(GPR &source, uint32 modify) {
|
||||
uint32 result = source - modify;
|
||||
uint32 overflow = ~(source ^ modify) & (source ^ result);
|
||||
cpsr().n = result >> 31;
|
||||
cpsr().z = result == 0;
|
||||
cpsr().c = (1u << 31) & (overflow ^ source ^ modify ^ result);
|
||||
cpsr().v = (1u << 31) & (overflow);
|
||||
}
|
||||
|
||||
void ARM::thumb_add(GPR &source, uint32 modify) {
|
||||
uint32 result = source + modify;
|
||||
uint32 overflow = ~(source ^ modify) & (source ^ result);
|
||||
cpsr().n = result >> 31;
|
||||
cpsr().z = result == 0;
|
||||
cpsr().c = (1u << 31) & (overflow ^ source ^ modify ^ result);
|
||||
cpsr().v = (1u << 31) & (overflow);
|
||||
source = result;
|
||||
}
|
||||
|
||||
void ARM::thumb_sub(GPR &source, uint32 modify) {
|
||||
uint32 result = source - modify;
|
||||
uint32 overflow = ~(source ^ modify) & (source ^ result);
|
||||
cpsr().n = result >> 31;
|
||||
cpsr().z = result == 0;
|
||||
cpsr().c = (1u << 31) & (overflow ^ source ^ modify ^ result);
|
||||
cpsr().v = (1u << 31) & (overflow);
|
||||
source = result;
|
||||
}
|
||||
|
||||
//(mov,cmp,add,sub) (rd,rn),#immediate
|
||||
//001o orrr iiii iiii
|
||||
//o = opcode
|
||||
//r = (rd,rn)
|
||||
//i = immediate
|
||||
void ARM::thumb_op_immediate() {
|
||||
uint2 opcode = instruction() >> 11;
|
||||
uint3 d = instruction() >> 8;
|
||||
uint8 immediate = instruction();
|
||||
|
||||
switch(opcode) {
|
||||
case 0: thumb_mov(r(d), immediate); break;
|
||||
case 1: thumb_cmp(r(d), immediate); break;
|
||||
case 2: thumb_add(r(d), immediate); break;
|
||||
case 3: thumb_sub(r(d), immediate); break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
void thumb_step();
|
||||
|
||||
void thumb_mov(GPR &source, uint32 modify);
|
||||
void thumb_cmp(GPR &source, uint32 modify);
|
||||
void thumb_add(GPR &source, uint32 modify);
|
||||
void thumb_sub(GPR &source, uint32 modify);
|
||||
|
||||
void thumb_op_immediate();
|
|
@ -9,7 +9,11 @@ void CPU::Enter() { cpu.enter(); }
|
|||
|
||||
void CPU::enter() {
|
||||
while(true) {
|
||||
step(2);
|
||||
if(exception) {
|
||||
print(disassemble_registers(), "\n");
|
||||
while(true) step(frequency);
|
||||
}
|
||||
cpsr().t ? thumb_step() : arm_step();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,42 +5,42 @@ namespace GBA {
|
|||
Bus bus;
|
||||
|
||||
uint32 StaticMemory::read(uint32 addr, uint32 size) {
|
||||
unsigned bits = addr & 3;
|
||||
addr &= ~3;
|
||||
|
||||
uint32 word = 0;
|
||||
switch(size) {
|
||||
case Word: word |= data[addr + 3] << 24;
|
||||
word |= data[addr + 2] << 16;
|
||||
case Half: word |= data[addr + 1] << 8;
|
||||
case Byte: word |= data[addr + 0] << 0;
|
||||
}
|
||||
|
||||
if(bits) {
|
||||
unsigned rotate = bits << 3;
|
||||
word = (word >> rotate) | (word << (32 - rotate));
|
||||
}
|
||||
|
||||
switch(size) {
|
||||
case Word: return word;
|
||||
case Half: return word & 0xffff;
|
||||
case Byte: return word & 0xff;
|
||||
case Word:
|
||||
addr &= ~3;
|
||||
word |= data[addr + 0] << 0;
|
||||
word |= data[addr + 1] << 8;
|
||||
word |= data[addr + 2] << 16;
|
||||
word |= data[addr + 3] << 24;
|
||||
break;
|
||||
case Half:
|
||||
addr &= ~1;
|
||||
word |= data[addr + 0] << 0;
|
||||
word |= data[addr + 1] << 8;
|
||||
break;
|
||||
case Byte:
|
||||
word |= data[addr + 0] << 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return word;
|
||||
}
|
||||
|
||||
void StaticMemory::write(uint32 addr, uint32 size, uint32 word) {
|
||||
switch(size) {
|
||||
case Word:
|
||||
addr &= ~3;
|
||||
data[addr + 3] = word >> 24;
|
||||
data[addr + 2] = word >> 16;
|
||||
data[addr + 1] = word >> 8;
|
||||
data[addr + 0] = word >> 0;
|
||||
data[addr + 1] = word >> 8;
|
||||
data[addr + 2] = word >> 16;
|
||||
data[addr + 3] = word >> 24;
|
||||
break;
|
||||
case Half:
|
||||
addr &= ~1;
|
||||
data[addr + 1] = word >> 8;
|
||||
data[addr + 0] = word >> 0;
|
||||
data[addr + 1] = word >> 8;
|
||||
break;
|
||||
case Byte:
|
||||
data[addr + 0] = word >> 0;
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
#include <gba/gba.hpp>
|
||||
|
||||
//pixel: 4 cycles
|
||||
|
||||
//hdraw: 240 pixels ( 960 cycles)
|
||||
//hblank: 68 pixels ( 272 cycles)
|
||||
//scanline: 308 pixels (1232 cycles)
|
||||
|
||||
//vdraw: 160 scanlines (197120 cycles)
|
||||
//vblank: 68 scanlines ( 83776 cycles)
|
||||
//frame: 208 scanlines (280896 cycles)
|
||||
|
||||
namespace GBA {
|
||||
|
||||
PPU ppu;
|
||||
|
@ -9,7 +19,7 @@ void PPU::Enter() { ppu.enter(); }
|
|||
void PPU::enter() {
|
||||
while(true) {
|
||||
frame();
|
||||
step(279620);
|
||||
step(280896);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
|
|||
uint4 rs = instruction >> 8;
|
||||
uint4 rm = instruction >> 0;
|
||||
|
||||
output.append(accumulate ? "mla" : "mul", condition[conditions], save ? "s " : " ");
|
||||
output.append(accumulate ? "mla" : "mul", conditions[condition], save ? "s " : " ");
|
||||
output.append(registers[rd], ",", registers[rm], ",", registers[rs]);
|
||||
if(accumulate) output.append(",", registers[rn]);
|
||||
|
||||
|
@ -40,7 +40,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
|
|||
uint1 psr = instruction >> 22;
|
||||
uint4 rd = instruction >> 12;
|
||||
|
||||
output.append("mrs", condition[conditions], " ");
|
||||
output.append("mrs", conditions[condition], " ");
|
||||
output.append(registers[rd], ",", psr ? "spsr" : "cpsr");
|
||||
|
||||
return output;
|
||||
|
@ -96,7 +96,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
|
|||
//{opcode}{condition}{s} rd,rm {shift} rs
|
||||
//{opcode}{condition} rn,rm {shift} rs
|
||||
//{opcode}{condition}{s} rd,rn,rm {shift} rs
|
||||
if((instruction & 0x0e000090) == 0x00000010) {
|
||||
if((instruction & 0x0e000090) == 0x00000010) {
|
||||
uint4 condition = instruction >> 28;
|
||||
uint4 opcode = instruction >> 21;
|
||||
uint1 save = instruction >> 20;
|
||||
|
@ -162,7 +162,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
|
|||
if(p == 0) output.append("]");
|
||||
if(immediate) output.append(",", u ? "+" : "-", "0x", hex<3>(immediate));
|
||||
if(p == 1) output.append("]");
|
||||
if(p == 1 && w == 1) output.append("!");
|
||||
if(p == 0 || w == 1) output.append("!");
|
||||
|
||||
if(rn == 15) output.append(" =0x", hex<8>(bus_readword(pc + 8 + (u ? +immediate : -immediate))));
|
||||
|
||||
|
@ -195,7 +195,7 @@ string ArmDSP::disassemble_opcode(uint32 pc) {
|
|||
if(mode == 3 && shift != 0) output.append(" ror #", shift);
|
||||
if(mode == 3 && shift == 0) output.append(" rrx");
|
||||
if(p == 1) output.append("]");
|
||||
if(p == 1 && w == 1) output.append("!");
|
||||
if(p == 0 || w == 1) output.append("!");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -239,7 +239,6 @@ string ArmDSP::disassemble_registers() {
|
|||
"r8:", hex<8>(r[ 8]), " r9:", hex<8>(r[ 9]), " r10:", hex<8>(r[10]), " r11:", hex<8>(r[11]),
|
||||
" r12:", hex<8>(r[12]), " r13:", hex<8>(r[13]), " r14:", hex<8>(r[14]), " r15:", hex<8>(r[15]), " ",
|
||||
"spsr:", spsr.n ? "N" : "n", spsr.z ? "Z" : "z", spsr.c ? "C" : "c", spsr.v ? "V" : "v"
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -233,7 +233,7 @@ void ArmDSP::op_data_register_shift() {
|
|||
uint1 save = instruction >> 20;
|
||||
uint4 s = instruction >> 8;
|
||||
uint2 mode = instruction >> 5;
|
||||
uint4 m = instruction >> 0;
|
||||
uint4 m = instruction;
|
||||
|
||||
uint8 rs = r[s];
|
||||
uint32 rm = r[m];
|
||||
|
@ -309,8 +309,8 @@ void ArmDSP::op_move_immediate_offset() {
|
|||
if(p == 0 || w == 1) r[n] = rn;
|
||||
}
|
||||
|
||||
//(ldr)(str){condition}{b} rd,[rn,rm {mode} #immediate]{!}
|
||||
//(ldr)(str){condition}{b} rd,[rn],rm {mode} #immediate
|
||||
//(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
|
||||
//p = pre (0 = post-indexed addressing)
|
||||
|
|
|
@ -86,6 +86,8 @@ struct Register {
|
|||
if(write) write();
|
||||
}
|
||||
|
||||
Register& operator=(const Register &source) { return operator=(source.data); }
|
||||
|
||||
Register& operator+=(uint32 n) { return operator=(data + n); }
|
||||
Register& operator-=(uint32 n) { return operator=(data - n); }
|
||||
Register& operator&=(uint32 n) { return operator=(data & n); }
|
||||
|
|
Loading…
Reference in New Issue