Update to v087r11 release.

byuu says:

Added all of the above fixes and changes. [A lot of individual fixes for
the ARM core from Cydrak - Ed.] Also new is pipeline_decode() to fetch
data, and IME/IE/IF support, and an ARM::processor.irqline flag that
triggers IRQs at 0x18. Only Vblank is hooked up, which is what SWI 4 was
waiting on previously.
I'm sure my interrupt support is horribly broken and wrong. I was never
able to really figure out IE/IF on the Game Boy, so there's no question
this is even worse.
It's now going crazy and writing 0 to IE forever now after the Vblank
IRQ triggers.
This commit is contained in:
Tim Allen 2012-03-29 22:58:10 +11:00
parent 5a1dcf5079
commit c66cc73374
18 changed files with 406 additions and 299 deletions

View File

@ -1,7 +1,7 @@
#ifndef BASE_HPP
#define BASE_HPP
static const char Version[] = "087.10";
static const char Version[] = "087.11";
#include <nall/platform.hpp>
#include <nall/algorithm.hpp>

View File

@ -2,20 +2,23 @@
namespace GBA {
#include "registers.cpp"
CPU cpu;
void CPU::Enter() { cpu.enter(); }
void CPU::enter() {
while(true) {
if(exception) {
if(crash) {
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();
processor.irqline = regs.ime && regs.irq_flag;
exec();
}
}
@ -44,17 +47,57 @@ void CPU::power() {
for(unsigned n = 0; n < iwram.size; n++) iwram.data[n] = 0;
for(unsigned n = 0; n < ewram.size; n++) ewram.data[n] = 0;
bus.mmio[0x0300] = this;
bus.mmio[0x0301] = this;
bus.mmio[0x0302] = this;
bus.mmio[0x0303] = this;
regs.ime = 0;
regs.irq_enable = 0;
regs.irq_flag = 0;
bus.mmio[0x130] = this;
bus.mmio[0x200] = this;
bus.mmio[0x202] = this;
bus.mmio[0x208] = this;
}
uint32 CPU::read(uint32 addr, uint32 size) {
uint32 result = 0;
switch(addr & 0x0ffffffc) {
case 0x04000130: //KEYINPUT
for(unsigned n = 0; n < 10; n++) result |= (interface->inputPoll(n) == false) << n;
if((result & 0xc0) == 0xc0) result &= ~0xc0; //up+down cannot be pressed simultaneously
if((result & 0x30) == 0x30) result &= ~0x30; //left+right cannot be pressed simultaneously
return result;
case 0x04000200: //IE
return regs.irq_enable;
case 0x04000202: //IF
return regs.irq_flag;
case 0x04000208: //IME
return regs.ime;
}
return 0u;
}
void CPU::write(uint32 addr, uint32 size, uint32 word) {
switch(addr & 0x0ffffffc) {
case 0x04000200: //IE
regs.irq_enable = word;
return;
case 0x04000202: //IF
regs.irq_flag = regs.irq_flag & ~word;
return;
case 0x04000208: //IME
regs.ime = word & 1;
return;
}
}
CPU::CPU() {

View File

@ -1,6 +1,7 @@
struct CPU : Processor::ARM, Thread, Memory {
StaticMemory iwram;
StaticMemory ewram;
#include "registers.hpp"
static void Enter();
void enter();

35
bsnes/gba/cpu/registers.cpp Executable file
View File

@ -0,0 +1,35 @@
CPU::Registers::Interrupt::operator uint16() const {
return (
(vblank << 0)
|| (hblank << 1)
|| (vcoincidence << 2)
|| (timer0 << 3)
|| (timer1 << 4)
|| (timer2 << 5)
|| (timer3 << 6)
|| (serial << 7)
|| (dma0 << 8)
|| (dma1 << 9)
|| (dma2 << 10)
|| (dma3 << 11)
|| (keypad << 12)
|| (cartridge << 13)
);
}
CPU::Registers::Interrupt& CPU::Registers::Interrupt::operator=(uint16 source) {
vblank = source & (1 << 0);
hblank = source & (1 << 1);
vcoincidence = source & (1 << 2);
timer0 = source & (1 << 3);
timer1 = source & (1 << 4);
timer2 = source & (1 << 5);
timer3 = source & (1 << 6);
serial = source & (1 << 7);
dma0 = source & (1 << 8);
dma1 = source & (1 << 9);
dma2 = source & (1 << 10);
dma3 = source & (1 << 11);
keypad = source & (1 << 12);
cartridge = source & (1 << 13);
}

23
bsnes/gba/cpu/registers.hpp Executable file
View File

@ -0,0 +1,23 @@
struct Registers {
bool ime;
struct Interrupt {
bool vblank;
bool hblank;
bool vcoincidence;
bool timer0;
bool timer1;
bool timer2;
bool timer3;
bool serial;
bool dma0;
bool dma1;
bool dma2;
bool dma3;
bool keypad;
bool cartridge;
operator uint16() const;
Interrupt& operator=(uint16 source);
} irq_enable, irq_flag;
} regs;

View File

@ -8,7 +8,7 @@
//vdraw: 160 scanlines (197120 cycles)
//vblank: 68 scanlines ( 83776 cycles)
//frame: 208 scanlines (280896 cycles)
//frame: 228 scanlines (280896 cycles)
namespace GBA {
@ -18,8 +18,8 @@ void PPU::Enter() { ppu.enter(); }
void PPU::enter() {
while(true) {
frame();
step(280896);
step(1232);
scanline();
}
}
@ -34,6 +34,27 @@ void PPU::power() {
for(unsigned n = 0; n < vram.size; n++) vram.data[n] = 0;
for(unsigned n = 0; n < oam.size; n++) oam.data[n] = 0;
for(unsigned n = 0; n < pram.size; n++) pram.data[n] = 0;
regs.scanline = 0;
bus.mmio[0x006] = this;
}
void PPU::scanline() {
regs.scanline++;
if(regs.scanline == 160) {
if(cpu.regs.ime && cpu.regs.irq_enable.vblank) {
cpu.regs.irq_flag.vblank = 1;
}
}
if(regs.scanline == 228) {
regs.scanline = 0;
frame();
}
if(regs.scanline >= 160) return;
}
void PPU::frame() {
@ -57,6 +78,11 @@ void PPU::frame() {
}
uint32 PPU::read(uint32 addr, uint32 size) {
if(addr == 0x04000006) {
//VCOUNT
return regs.scanline;
}
return 0u;
}

View File

@ -3,11 +3,16 @@ struct PPU : Thread, Memory {
StaticMemory oam;
StaticMemory pram;
struct Registers {
unsigned scanline;
} regs;
static void Enter();
void enter();
void step(unsigned clocks);
void power();
void scanline();
void frame();
uint32 read(uint32 addr, uint32 size);

View File

@ -18,3 +18,121 @@ bool ARM::condition(uint4 condition) {
case 15: return false; //NV (never)
}
}
uint32 ARM::bit(uint32 result) {
if(cpsr().t || instruction() & (1 << 20)) {
cpsr().n = result >> 31;
cpsr().z = result == 0;
cpsr().c = carryout();
}
return result;
}
uint32 ARM::add(uint32 source, uint32 modify, bool carry) {
uint32 result = source + modify + carry;
if(cpsr().t || instruction() & (1 << 20)) {
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;
}
uint32 ARM::sub(uint32 source, uint32 modify, bool carry) {
return add(source, ~modify, carry);
}
uint32 ARM::mul(uint32 product, uint32 multiplicand, uint32 multiplier) {
//Modified Booth Encoding
bool carry = 0;
unsigned place = 0;
do {
step(1);
signed factor = (int2)multiplier + carry;
if(factor == -2) product -= multiplicand << (place + 1);
if(factor == -1) product -= multiplicand << (place + 0);
if(factor == +1) product += multiplicand << (place + 0);
if(factor == +2) product += multiplicand << (place + 1);
carry = multiplier & 2;
place += 2;
multiplier >>= 2;
} while(multiplier + carry && place < 32);
if(cpsr().t || instruction() & (1 << 20)) {
cpsr().n = product >> 31;
cpsr().z = product == 0;
cpsr().c = carry;
}
return product;
}
uint32 ARM::lsl(uint32 source, uint32 shift) {
while(shift--) {
carryout() = source >> 31;
source <<= 1;
}
if(cpsr().t) {
cpsr().n = source >> 31;
cpsr().z = source == 0;
cpsr().c = carryout();
}
return source;
}
uint32 ARM::lsr(uint32 source, uint32 shift) {
while(shift--) {
carryout() = source & 1;
source >>= 1;
}
if(cpsr().t) {
cpsr().n = source >> 31;
cpsr().z = source == 0;
cpsr().c = carryout();
}
return source;
}
uint32 ARM::asr(uint32 source, uint32 shift) {
while(shift--) {
carryout() = source & 1;
source = (int32)source >> 1;
}
if(cpsr().t) {
cpsr().n = source >> 31;
cpsr().z = source == 0;
cpsr().c = carryout();
}
return source;
}
uint32 ARM::ror(uint32 source, uint32 shift) {
while(shift--) {
carryout() = source & 1;
source = (source << 31) | (source >> 1);
}
if(cpsr().t) {
cpsr().n = source >> 31;
cpsr().z = source == 0;
cpsr().c = carryout();
}
return source;
}
uint32 ARM::rrx(uint32 source) {
carryout() = source & 1;
source = (cpsr().c << 31) | (source >> 1);
}

View File

@ -13,7 +13,7 @@ void ARM::power() {
processor.power();
vector(0x00000000, Processor::Mode::SVC);
pipeline.reload = true;
exception = false;
crash = false;
r(15).modify = [&] {
pipeline.reload = true;
r(15).data &= cpsr().t ? ~1 : ~3;
@ -23,6 +23,15 @@ void ARM::power() {
instructions = 0;
}
void ARM::exec() {
if(processor.irqline && cpsr().i == 0) {
vector(0x00000018, Processor::Mode::IRQ);
r(14) += 4;
}
cpsr().t ? thumb_step() : arm_step();
}
void ARM::vector(uint32 addr, Processor::Mode mode) {
auto psr = cpsr();
processor.setMode(mode);

View File

@ -16,8 +16,19 @@ struct ARM {
virtual void bus_write(uint32 addr, uint32 size, uint32 word) = 0;
void power();
void exec();
void vector(uint32 addr, Processor::Mode mode);
bool condition(uint4 condition);
uint32 bit(uint32 result);
uint32 add(uint32 source, uint32 modify, bool carry);
uint32 sub(uint32 source, uint32 modify, bool carry);
uint32 mul(uint32 product, uint32 multiplicand, uint32 multiplier);
uint32 lsl(uint32 source, uint32 shift);
uint32 lsr(uint32 source, uint32 shift);
uint32 asr(uint32 source, uint32 shift);
uint32 ror(uint32 source, uint32 shift);
uint32 rrx(uint32 source);
void serialize(serializer&);

View File

@ -746,12 +746,14 @@ 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("cpsr:", cpsr().n ? "N" : "n", cpsr().z ? "Z" : "z", cpsr().c ? "C" : "c", cpsr().v ? "V" : "v");
output.append("/", hex<2>(cpsr().m), "\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; }
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");
output.append("/", hex<2>(spsr().m));
return output;
}

View File

@ -7,18 +7,11 @@ void ARM::arm_step() {
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);
pipeline_step();
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);
pipeline_step();
step(2);
instructions++;
@ -34,21 +27,19 @@ void ARM::arm_step() {
== 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("???? 0001 0?00 ++++ ???? ---- 0000 ----", move_to_register_from_status);
decode("???? 0001 0?00 ???? ???? ---- 1001 ????", memory_swap);
decode("???? 000? ?0?? ???? ???? ---- 1011 ????", move_half_register);
decode("???? 000? ?1?? ???? ???? ???? 1011 ????", move_half_immediate);
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("???? 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?? ???? ???? ---- 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("???? 0011 0?10 ???? ++++ ???? ???? ????", move_to_status_from_immediate);
decode("???? 010? ???? ???? ???? ???? ???? ????", move_immediate_offset);
decode("???? 011? ???? ???? ???? ???? ???0 ????", move_register_offset);
decode("???? 100? ???? ???? ???? ???? ???? ????", move_multiple);
@ -57,7 +48,7 @@ void ARM::arm_step() {
#undef decode
exception = true;
crash = true;
}
void ARM::arm_opcode(uint32 rm) {
@ -68,44 +59,28 @@ void ARM::arm_opcode(uint32 rm) {
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
case 0: r(d) = bit(rn & rm); break; //AND
case 1: r(d) = bit(rn ^ rm); break; //EOR
case 2: r(d) = sub(rn, rm, 1); break; //SUB
case 3: r(d) = sub(rm, rn, 1); break; //RSB
case 4: r(d) = add(rn, rm, 0); break; //ADD
case 5: r(d) = add(rn, rm, cpsr().c); break; //ADC
case 6: r(d) = sub(rn, rm, cpsr().c); break; //SBC
case 7: r(d) = sub(rm, rn, cpsr().c); break; //RSC
case 8: bit(rn & rm); break; //TST
case 9: bit(rn ^ rm); break; //TEQ
case 10: sub(rn, rm, 1); break; //CMP
case 11: add(rn, rm, 0); break; //CMN
case 12: r(d) = bit(rn | rm); break; //ORR
case 13: r(d) = bit(rm); break; //MOV
case 14: r(d) = bit(rn & ~rm); break; //BIC
case 15: r(d) = bit(~rm); break; //MVN
}
if(exceptionmode() && d == 15 && save) {
cpsr() = spsr();
processor.setMode((Processor::Mode)cpsr().m);
}
}
@ -121,7 +96,7 @@ void ARM::arm_move_to_status(uint32 rm) {
PSR &psr = source ? spsr() : cpsr();
if(field & 1) {
if(source == 1 || (Processor::Mode)cpsr().m != Processor::Mode::USR) {
if(source == 1 || privilegedmode()) {
psr.i = rm & 0x00000080;
psr.f = rm & 0x00000040;
psr.t = rm & 0x00000020;
@ -138,45 +113,6 @@ void ARM::arm_move_to_status(uint32 rm) {
}
}
//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
@ -189,42 +125,14 @@ void ARM::rrx(bool &c, uint32 &rm) {
//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;
auto &rd = r(d);
uint32 rs = r(s);
auto &rm = r(m);
rd = accumulate ? r(n) : 0u;
r(d) = accumulate ? r(n) : 0u;
step(1);
//Modified Booth Encoding
bool carry = 0;
unsigned place = 0;
do {
step(1);
signed factor = (int2)rs + carry;
if(factor == -2) rd -= rm << (place + 1);
if(factor == -1) rd -= rm << (place + 0);
if(factor == +1) rd += rm << (place + 0);
if(factor == +2) rd += rm << (place + 1);
carry = rs & 2;
place += 2;
rs >>= 2;
} while(rs + carry && place < 32);
if(save) {
cpsr().n = r(d) >> 31;
cpsr().z = r(d) == 0;
cpsr().c = carry;
}
r(d) = mul(r(d), r(m), r(s));
}
//swp{condition}{b} rd,rm,[rn]
@ -269,8 +177,8 @@ void ARM::arm_op_move_half_register() {
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(load == 1) r(d) = bus_read(rn, Half);
if(load == 0) bus_write(rn, Half, r(d));
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback == 1) r(n) = rn;
@ -302,8 +210,8 @@ void ARM::arm_op_move_half_immediate() {
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(load == 1) r(d) = bus_read(rn, Half);
if(load == 0) bus_write(rn, Half, r(d));
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
if(pre == 0 || writeback == 1) r(n) = rn;
@ -335,7 +243,7 @@ void ARM::arm_op_load_register() {
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) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback == 1) r(n) = rn;
}
@ -425,8 +333,7 @@ void ARM::arm_op_move_to_status_from_immediate() {
uint8 immediate = instruction();
uint32 rm = immediate;
bool c = cpsr().c;
if(rotate) ror(c, rm, 2 * rotate);
if(rotate) rm = ror(rm, 2 * rotate);
arm_move_to_status(rm);
}
@ -451,14 +358,12 @@ void ARM::arm_op_data_immediate_shift() {
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);
if(mode == 0) rm = lsl(rm, rs);
if(mode == 1) rm = lsr(rm, rs ? rs : 32);
if(mode == 2) rm = asr(rm, rs ? rs : 32);
if(mode == 3) rm = rs ? ror(rm, rs) : rrx(rm);
carryout() = c;
arm_opcode(rm);
}
@ -482,14 +387,12 @@ void ARM::arm_op_data_register_shift() {
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);
if(mode == 0 ) rm = lsl(rm, rs < 33 ? rs : 33);
if(mode == 1 ) rm = lsr(rm, rs < 33 ? rs : 33);
if(mode == 2 ) rm = asr(rm, rs < 32 ? rs : 32);
if(mode == 3 && rs) rm = ror(rm, rs & 31 == 0 ? 32 : rs & 31);
carryout() = c;
arm_opcode(rm);
}
@ -584,10 +487,10 @@ void ARM::arm_op_move_register_offset() {
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(mode == 0) rm = lsl(rm, rs);
if(mode == 1) rm = lsr(rm, rs ? rs : 32);
if(mode == 2) rm = asr(rm, rs ? rs : 32);
if(mode == 3) rm = rs ? ror(rm, rs) : rrx(rm);
if(pre == 1) rn = up ? rn + rm : rn - rm;
if(load) {

View File

@ -1,15 +1,8 @@
void arm_step();
bool arm_condition();
void arm_opcode(uint32 rm);
void arm_move_to_status(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_memory_swap();
void arm_op_move_half_register();

View File

@ -7,18 +7,11 @@ void ARM::thumb_step() {
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);
pipeline_step();
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);
pipeline_step();
step(1);
instructions++;
@ -57,98 +50,30 @@ void ARM::thumb_step() {
#undef decode
exception = true;
crash = true;
}
void ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) {
switch(opcode) {
case 0: r(d) = thumb_tst(r(d) & r(m)); break; //AND
case 1: r(d) = thumb_tst(r(d) ^ r(m)); break; //EOR
case 2: r(d) = thumb_lsl(r(d), r(m) & 0xff); break; //LSL
case 3: r(d) = thumb_lsr(r(d), r(m) & 0xff); break; //LSR
case 4: r(d) = thumb_asr(r(d), r(m) & 0xff); break; //ASR
case 5: r(d) = thumb_add(r(d), r(m), cpsr().c); break; //ADC
case 6: r(d) = thumb_sub(r(d), r(m), cpsr().c); break; //SBC
case 7: r(d) = thumb_ror(r(d), r(m) & 0xff); break; //ROR
case 8: thumb_tst(r(d) & r(m)); break; //TST
case 9: r(d) = thumb_sub(0, r(m)); break; //NEG
case 10: thumb_sub(r(d), r(m)); break; //CMP
case 11: thumb_add(r(d), r(m)); break; //CMN
case 12: r(d) = thumb_tst(r(d) | r(m)); break; //ORR
case 13: r(d) = thumb_mul(r(d), r(m)); break; //MUL
case 14: r(d) = thumb_tst(r(d) & ~r(m)); break; //BIC
case 15: r(d) = thumb_tst(~r(m)); break; //MVN
case 0: r(d) = bit(r(d) & r(m)); break; //AND
case 1: r(d) = bit(r(d) ^ r(m)); break; //EOR
case 2: r(d) = lsl(r(d), r(m) & 0xff); break; //LSL
case 3: r(d) = lsr(r(d), r(m) & 0xff); break; //LSR
case 4: r(d) = asr(r(d), r(m) & 0xff); break; //ASR
case 5: r(d) = add(r(d), r(m), cpsr().c); break; //ADC
case 6: r(d) = sub(r(d), r(m), cpsr().c); break; //SBC
case 7: r(d) = ror(r(d), r(m) & 0xff); break; //ROR
case 8: bit(r(d) & r(m)); break; //TST
case 9: r(d) = sub(0, r(m), 1); break; //NEG
case 10: sub(r(d), r(m), 1); break; //CMP
case 11: add(r(d), r(m), 0); break; //CMN
case 12: r(d) = bit(r(d) | r(m)); break; //ORR
case 13: r(d) = mul(0, r(d), r(m)); break; //MUL
case 14: r(d) = bit(r(d) & ~r(m)); break; //BIC
case 15: r(d) = bit(~r(m)); break; //MVN
}
}
uint32 ARM::thumb_tst(uint32 modify) {
cpsr().n = modify >> 31;
cpsr().z = modify == 0;
return modify;
}
uint32 ARM::thumb_add(uint32 source, uint32 modify, bool carry) {
uint32 result = source + modify + carry;
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;
}
uint32 ARM::thumb_sub(uint32 source, uint32 modify, bool carry) {
thumb_add(source, ~modify, carry);
}
uint32 ARM::thumb_lsl(uint32 source, uint32 modify) {
while(modify--) {
cpsr().c = source >> 31;
source <<= 1;
}
cpsr().n = source >> 31;
cpsr().z = source == 0;
return source;
}
uint32 ARM::thumb_lsr(uint32 source, uint32 modify) {
while(modify--) {
cpsr().c = source & 1;
source >>= 1;
}
cpsr().n = source >> 31;
cpsr().z = source == 0;
return source;
}
uint32 ARM::thumb_asr(uint32 source, uint32 modify) {
while(modify--) {
cpsr().c = source & 1;
source = (int32)source >> 1;
}
cpsr().n = source >> 31;
cpsr().z = source == 0;
return source;
}
uint32 ARM::thumb_ror(uint32 source, uint32 modify) {
while(modify--) {
cpsr().c = source & 1;
source = (source << 31) | (source >> 1);
}
cpsr().n = source >> 31;
cpsr().z = source == 0;
return source;
}
uint32 ARM::thumb_mul(uint32 source, uint32 modify) {
source = source * modify;
cpsr().n = source >> 31;
cpsr().z = source == 0;
cpsr().c = 0;
return source;
}
//(add,sub) rd,rn,rm
//0001 10om mmnn nddd
//o = opcode
@ -162,8 +87,8 @@ void ARM::thumb_op_adjust_register() {
uint3 d = instruction() >> 0;
switch(opcode) {
case 0: r(d) = thumb_add(r(n), r(m)); break;
case 1: r(d) = thumb_sub(r(n), r(m)); break;
case 0: r(d) = add(r(n), r(m), 0); break;
case 1: r(d) = sub(r(n), r(m), 1); break;
}
}
@ -180,8 +105,8 @@ void ARM::thumb_op_adjust_immediate() {
uint3 d = instruction() >> 0;
switch(opcode) {
case 0: r(d) = thumb_add(r(n), immediate); break;
case 1: r(d) = thumb_sub(r(n), immediate); break;
case 0: r(d) = add(r(n), immediate, 0); break;
case 1: r(d) = sub(r(n), immediate, 1); break;
}
}
@ -198,9 +123,9 @@ void ARM::thumb_op_shift_immediate() {
uint3 d = instruction() >> 0;
switch(opcode) {
case 0: r(d) = thumb_lsl(r(m), immediate); break;
case 1: r(d) = thumb_lsr(r(m), immediate); break;
case 2: r(d) = thumb_asr(r(m), immediate); break;
case 0: r(d) = lsl(r(m), immediate); break;
case 1: r(d) = lsr(r(m), immediate); break;
case 2: r(d) = asr(r(m), immediate); break;
}
}
@ -215,10 +140,10 @@ void ARM::thumb_op_immediate() {
uint8 immediate = instruction();
switch(opcode) {
case 0: r(d) = thumb_tst( immediate); break;
case 1: thumb_sub(r(d), immediate); break;
case 2: r(d) = thumb_add(r(d), immediate); break;
case 3: r(d) = thumb_sub(r(d), immediate); break;
case 0: r(d) = bit( immediate ); break;
case 1: sub(r(d), immediate, 1); break;
case 2: r(d) = add(r(d), immediate, 0); break;
case 3: r(d) = sub(r(d), immediate, 1); break;
}
}
@ -258,9 +183,9 @@ void ARM::thumb_op_alu_hi() {
uint4 d = (dh << 3) + (dl << 0);
switch(opcode) {
case 0: r(d) = thumb_add(r(d), r(m)); break; //ADD
case 1: thumb_sub(r(d), r(m)); break; //SUB
case 2: r(d) = thumb_tst( r(m)); break; //MOV
case 0: r(d) = r(d) + r(m); break; //ADD (does not modify flags)
case 1: sub(r(d), r(m), 1); break; //SUB
case 2: r(d) = r(m); break; //MOV (does not modify flags)
}
}
@ -313,7 +238,7 @@ void ARM::thumb_op_move_word_immediate() {
uint3 d = instruction() >> 0;
if(load == 1) r(d) = bus_read(r(n) + offset * 4, Word);
if(load == 0) bus_write(r(d) + offset * 4, Word, r(n));
if(load == 0) bus_write(r(n) + offset * 4, Word, r(d));
}
//(ldr,str)b rd,[rn,#offset]
@ -326,10 +251,10 @@ void ARM::thumb_op_move_byte_immediate() {
uint1 load = instruction() >> 11;
uint5 offset = instruction() >> 6;
uint3 n = instruction() >> 3;
uint4 d = instruction() >> 0;
uint3 d = instruction() >> 0;
if(load == 1) r(d) = bus_read(r(n) + offset, Byte);
if(load == 0) bus_write(r(d) + offset, Byte, r(n));
if(load == 0) bus_write(r(n) + offset, Byte, r(d));
}
//(ldr,str)h rd,[rn,#offset]
@ -345,21 +270,21 @@ void ARM::thumb_op_move_half_immediate() {
uint3 d = instruction() >> 0;
if(load == 1) r(d) = bus_read(r(n) + offset * 2, Half);
if(load == 0) bus_write(r(d) + offset * 2, Half, r(n));
if(load == 0) bus_write(r(n) + offset * 2, Half, r(d));
}
//(ldr,str) rd,[sp,#relative]
//1001 oddd rrrr rrrr
//(ldr,str) rd,[sp,#immediate]
//1001 oddd iiii iiii
//o = opcode
//d = rd
//r = relative
//i = immediate
void ARM::thumb_op_move_stack() {
uint1 opcode = instruction() >> 11;
uint3 d = instruction() >> 8;
int8 relative = instruction();
uint8 immediate = instruction();
if(opcode == 0) bus_write(r(13) + relative * 4, Word, r(d));
if(opcode == 1) r(d) = bus_read(r(13) + relative * 4, Word);
if(opcode == 0) bus_write(r(13) + immediate * 4, Word, r(d));
if(opcode == 1) r(d) = bus_read(r(13) + immediate * 4, Word);
}
//add rd,{pc,sp},#immediate

View File

@ -1,17 +1,7 @@
void thumb_step();
bool thumb_condition(uint4 condition);
void thumb_opcode(uint4 opcode, uint4 d, uint4 s);
uint32 thumb_tst(uint32 modify);
uint32 thumb_add(uint32 source, uint32 modify, bool carry = 0);
uint32 thumb_sub(uint32 source, uint32 modify, bool carry = 1);
uint32 thumb_lsl(uint32 source, uint32 modify);
uint32 thumb_lsr(uint32 source, uint32 modify);
uint32 thumb_asr(uint32 source, uint32 modify);
uint32 thumb_ror(uint32 source, uint32 modify);
uint32 thumb_mul(uint32 source, uint32 modify);
void thumb_op_adjust_register();
void thumb_op_adjust_immediate();
void thumb_op_shift_immediate();

View File

@ -10,6 +10,9 @@ void ARM::Processor::power() {
und.sp = und.lr = 0;
pc = 0;
carryout = false;
irqline = false;
cpsr = 0;
spsr = nullptr;
fiq.spsr = 0;
@ -31,7 +34,7 @@ void ARM::Processor::power() {
}
void ARM::Processor::setMode(Mode mode) {
cpsr.m = (unsigned)mode;
cpsr.m = 0x10 | (unsigned)mode;
if(mode == Mode::FIQ) {
r[ 8] = &fiq.r8;
@ -57,4 +60,19 @@ void ARM::Processor::setMode(Mode mode) {
}
}
void ARM::pipeline_step() {
pipeline.execute = pipeline.decode;
pipeline.decode = pipeline.fetch;
if(cpsr().t == 0) {
r(15).data += 4;
pipeline.fetch.address = r(15);
pipeline.fetch.instruction = bus_read(r(15), Word);
} else {
r(15).data += 2;
pipeline.fetch.address = r(15);
pipeline.fetch.instruction = bus_read(r(15), Half);
}
}
#endif

View File

@ -104,6 +104,7 @@ struct Processor {
GPR pc;
PSR cpsr;
bool carryout;
bool irqline;
GPR *r[16];
PSR *spsr;
@ -114,7 +115,9 @@ struct Processor {
Processor processor;
Pipeline pipeline;
bool exception;
bool crash;
void pipeline_step();
alwaysinline GPR& r(unsigned n) { return *processor.r[n]; }
alwaysinline PSR& cpsr() { return processor.cpsr; }
@ -122,3 +125,5 @@ 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; }
alwaysinline bool privilegedmode() const { return (Processor::Mode)processor.cpsr.m != Processor::Mode::USR; }
alwaysinline bool exceptionmode() const { return privilegedmode() && (Processor::Mode)processor.cpsr.m != Processor::Mode::SYS; }

View File

@ -27,7 +27,7 @@ void ArmDSP::enter() {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
}
if(exception) {
if(crash) {
print(disassemble_arm_instruction(pipeline.execute.address), "\n");
print(disassemble_registers(), "\n");
print("Executed: ", instructions, "\n");