Update to v087r25 release.

byuu says:

(r24 was a point release during merging of changes.)

This release is almost entirely Cydrak's direct work:
- Added ARM::sequential() and some WAITCNT timings
- Added Bus::io(uint32 pc), intended for prefetch timing
- Added ARM::load() with data rotation (fixed Mother 3 graphics)
- Added ARM::store() for data mirroring
- LDM, STM, and instruction fetch still use read/write()
- ARM::vector() no longer unmasks FIQs
- Set THUMB shifter flags via bit(), consistent with ARM
- Replace shifter loops with conditional tests

My changes:
- fixed sprite clipping on left-edge of screen
- added first system folder, GBA.system
- sudo make install is now make install
- make install will create GBA.system for you in your home folder

Windows users, take data/GBA.system and put it in the same folder as
bsnes.exe, and give it a BIOS named bios.rom
Or place it in your home folder (%APPDATA%/bsnes)
Also note that this is highly experimental, I'll probably be changing
things a lot before release.

EDIT: I botched the cartridge timing change. Will fix in r26. It'll
still run a bit too fast for now, unfortunately.
This commit is contained in:
Tim Allen 2012-04-15 16:49:56 +10:00
parent 28885db586
commit 1c18812f47
22 changed files with 276 additions and 216 deletions

View File

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

View File

@ -0,0 +1,4 @@
<?xml version='1.0' encoding='UTF-8'?>
<system type="GBA">
<bios firmware="bios.rom" sha256="fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570"/>
</system>

View File

@ -45,6 +45,11 @@ void CPU::step(unsigned clocks) {
if(apu.clock < 0) co_switch(apu.thread);
}
void CPU::bus_idle(uint32 addr) {
step(1);
return bus.idle(addr);
}
uint32 CPU::bus_read(uint32 addr, uint32 size) {
step(bus.speed(addr, size));
return bus.read(addr, size);

View File

@ -8,6 +8,7 @@ struct CPU : Processor::ARM, Thread, MMIO {
void enter();
void step(unsigned clocks);
void bus_idle(uint32 addr);
uint32 bus_read(uint32 addr, uint32 size);
void bus_write(uint32 addr, uint32 size, uint32 word);

View File

@ -112,13 +112,13 @@ uint16 CPU::Registers::Interrupt::operator=(uint16 source) {
CPU::Registers::WaitControl::operator uint16() const {
return (
(sram << 0)
| (wait0n << 2)
| (wait0s << 4)
| (wait1n << 5)
| (wait1s << 7)
| (wait2n << 8)
| (wait2s << 10)
(nwait[3] << 0)
| (nwait[0] << 2)
| (swait[0] << 4)
| (nwait[1] << 5)
| (swait[1] << 7)
| (nwait[2] << 8)
| (swait[2] << 10)
| (phi << 11)
| (prefetch << 14)
| (gametype << 15)
@ -126,16 +126,17 @@ CPU::Registers::WaitControl::operator uint16() const {
}
uint16 CPU::Registers::WaitControl::operator=(uint16 source) {
sram = (source >> 0) & 3;
wait0n = (source >> 2) & 3;
wait0s = (source >> 4) & 1;
wait1n = (source >> 5) & 3;
wait1s = (source >> 7) & 1;
wait2n = (source >> 8) & 3;
wait2s = (source >> 10) & 1;
nwait[3] = (source >> 0) & 3;
nwait[0] = (source >> 2) & 3;
swait[0] = (source >> 4) & 1;
nwait[1] = (source >> 5) & 3;
swait[1] = (source >> 7) & 1;
nwait[2] = (source >> 8) & 3;
swait[2] = (source >> 10) & 1;
phi = (source >> 11) & 3;
prefetch = (source >> 14) & 1;
gametype = (source >> 15) & 1;
swait[3] = nwait[3];
return operator uint16();
}

View File

@ -91,13 +91,8 @@ struct Registers {
} irq;
struct WaitControl {
uint2 sram;
uint2 wait0n;
uint1 wait0s;
uint2 wait1n;
uint1 wait1s;
uint2 wait2n;
uint1 wait2s;
uint2 nwait[4];
uint2 swait[4];
uint2 phi;
uint1 prefetch;
uint1 gametype;

View File

@ -74,62 +74,77 @@ uint32 Bus::mirror(uint32 addr, uint32 size) {
}
uint32 Bus::speed(uint32 addr, uint32 size) {
return 2;
if(addr & 0x08000000) {
static unsigned timing[] = { 5, 4, 3, 9 };
unsigned n = cpu.regs.wait.control.nwait[addr >> 25 & 3];
unsigned s = cpu.regs.wait.control.swait[addr >> 25 & 3];
//B B E I M P V O R R R R R R S S
//I I R R M R R A O O O O O O R R
//O O A A I A A M M M M M M M A A
//S S M M O M M M M
static unsigned byte[] = { 1, 1, 3, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 5 };
static unsigned half[] = { 1, 1, 3, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 5 };
static unsigned word[] = { 1, 1, 6, 1, 1, 2, 2, 1, 8, 8, 8, 8, 8, 8, 8, 8 };
bool sequential = cpu.sequential();
if((addr & 0xffff << 1) == 0) sequential = false;
if(idleflag) sequential = false;
addr = (addr >> 24) & 15;
switch(size) {
case Byte: return byte[addr];
case Half: return half[addr];
case Word: return word[addr];
if(sequential) return s << (size == Word); //16-bit bus
if(size == Word) n += s;
return n;
}
switch(addr >> 24 & 7) {
case 0: return 1;
case 1: return 1;
case 2: return 3 << (size == Word);
case 3: return 1;
case 4: return 1;
case 5: return 1 << (size == Word);
case 6: return 1 << (size == Word);
case 7: return 1;
}
}
void Bus::idle(uint32 addr) {
if(addr & 0x08000000) idleflag = true;
}
uint32 Bus::read(uint32 addr, uint32 size) {
idleflag = false;
if(addr & 0x08000000) return cartridge.read(addr, size);
switch(addr & 0x07000000) {
case 0x00000000: return bios.read(addr, size);
case 0x01000000: return bios.read(addr, size);
case 0x02000000: return cpu.ewram.read(addr & 0x3ffff, size);
case 0x03000000: return cpu.iwram.read(addr & 0x7fff, size);
case 0x04000000:
switch(addr >> 24 & 7) {
case 0: return bios.read(addr, size);
case 1: return bios.read(addr, size);
case 2: return cpu.ewram.read(addr & 0x3ffff, size);
case 3: return cpu.iwram.read(addr & 0x7fff, size);
case 4:
if((addr & 0xfffffc00) == 0x04000000) return mmio[addr & 0x3ff]->read(addr, size);
if((addr & 0xff00ffff) == 0x04000800) return ((MMIO&)cpu).read(0x04000800 | (addr & 3), size);
return 0u;
case 0x05000000: return ppu.pram_read(addr, size);
case 0x06000000: return ppu.vram_read(addr, size);
case 0x07000000: return ppu.oam_read(addr, size);
case 5: return ppu.pram_read(addr, size);
case 6: return ppu.vram_read(addr, size);
case 7: return ppu.oam_read(addr, size);
}
}
void Bus::write(uint32 addr, uint32 size, uint32 word) {
idleflag = false;
if(addr & 0x08000000) return cartridge.write(addr, size, word);
switch(addr & 0x07000000) {
case 0x00000000: return;
case 0x01000000: return;
case 0x02000000: return cpu.ewram.write(addr & 0x3ffff, size, word);
case 0x03000000: return cpu.iwram.write(addr & 0x7fff, size, word);
case 0x04000000:
switch(addr >> 24 & 7) {
case 0: return;
case 1: return;
case 2: return cpu.ewram.write(addr & 0x3ffff, size, word);
case 3: return cpu.iwram.write(addr & 0x7fff, size, word);
case 4:
if((addr & 0xfffffc00) == 0x04000000) return mmio[addr & 0x3ff]->write(addr, size, word);
if((addr & 0xff00ffff) == 0x04000800) return ((MMIO&)cpu).write(0x04000800 | (addr & 3), size, word);
return;
case 0x05000000: return ppu.pram_write(addr, size, word);
case 0x06000000: return ppu.vram_write(addr, size, word);
case 0x07000000: return ppu.oam_write(addr, size, word);
case 5: return ppu.pram_write(addr, size, word);
case 6: return ppu.vram_write(addr, size, word);
case 7: return ppu.oam_write(addr, size, word);
}
}
void Bus::power() {
for(unsigned n = 0; n < 0x400; n++) mmio[n] = &unmappedMemory;
idleflag = false;
}
}

View File

@ -23,9 +23,11 @@ struct MMIO : Memory {
struct Bus : Memory {
Memory *mmio[0x400];
bool idleflag;
static uint32 mirror(uint32 addr, uint32 size);
uint32 speed(uint32 addr, uint32 size);
void idle(uint32 addr);
uint32 read(uint32 addr, uint32 size);
void write(uint32 addr, uint32 size, uint32 word);
void power();

View File

@ -56,7 +56,7 @@ void PPU::render_object(Object &obj) {
x = (x / (1 + regs.mosaic.objhsize)) * (1 + regs.mosaic.objhsize);
}
unsigned ox = obj.x + px;
uint9 ox = obj.x + px;
if(ox < 240 && x < obj.width && y < obj.height) {
unsigned offset = (y / 8) * rowsize + (x / 8);
offset = offset * 64 + (y & 7) * 8 + (x & 7);

View File

@ -55,63 +55,40 @@ uint32 ARM::mul(uint32 product, uint32 multiplicand, uint32 multiplier) {
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();
}
uint32 ARM::lsl(uint32 source, uint8 shift) {
carryout() = cpsr().c;
if(shift == 0) return source;
carryout() = shift > 32 ? 0 : source & (1 << 32 - shift);
source = shift > 31 ? 0 : source << shift;
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();
}
uint32 ARM::lsr(uint32 source, uint8 shift) {
carryout() = cpsr().c;
if(shift == 0) return source;
carryout() = shift > 32 ? 0 : source & (1 << shift - 1);
source = shift > 31 ? 0 : source >> shift;
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();
}
uint32 ARM::asr(uint32 source, uint8 shift) {
carryout() = cpsr().c;
if(shift == 0) return source;
carryout() = shift > 32 ? source & (1 << 31) : source & (1 << shift - 1);
source = shift > 31 ? (int32)source >> 31 : (int32)source >> shift;
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();
}
uint32 ARM::ror(uint32 source, uint8 shift) {
carryout() = cpsr().c;
if(shift == 0) return source;
if(shift &= 31)
source = source << 32 - shift | source >> shift;
carryout() = source & (1 << 31);
return source;
}

View File

@ -26,16 +26,43 @@ void ARM::exec() {
cpsr().t ? thumb_step() : arm_step();
}
void ARM::idle() {
bus_idle(r(15));
}
uint32 ARM::read(uint32 addr, uint32 size) {
uint32 word = bus_read(addr, size);
//uint32 rotate = (addr & 3) << 3;
//word = (word >> rotate) | (word << (32 - rotate));
//word = word & (~0u >> (32 - size));
sequential() = true;
return word;
}
uint32 ARM::load(uint32 addr, uint32 size) {
sequential() = false;
uint32 word = read(addr, size);
if(size == Half) { word &= 0xffff; word |= word << 16; }
if(size == Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
word = ror(word, 8 * (addr & 3));
idle();
if(size == Half) word &= 0xffff;
if(size == Byte) word &= 0xff;
return word;
}
void ARM::write(uint32 addr, uint32 size, uint32 word) {
return bus_write(addr, size, word);
bus_write(addr, size, word);
sequential() = true;
}
void ARM::store(uint32 addr, uint32 size, uint32 word) {
if(size == Half) { word &= 0xffff; word |= word << 16; }
if(size == Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
sequential() = false;
write(addr, size, word);
sequential() = false;
}
void ARM::vector(uint32 addr, Processor::Mode mode) {
@ -43,7 +70,7 @@ void ARM::vector(uint32 addr, Processor::Mode mode) {
processor.setMode(mode);
spsr() = psr;
cpsr().i = 1;
cpsr().f = mode == Processor::Mode::FIQ;
cpsr().f |= mode == Processor::Mode::FIQ;
cpsr().t = 0;
r(14) = pipeline.decode.address;
r(15) = addr;

View File

@ -3,7 +3,8 @@
namespace Processor {
//ARMv3, ARMv4TM
//ARMv3
//ARMv4TDMI
struct ARM {
enum : unsigned { Byte = 8, Half = 16, Word = 32 };
@ -12,13 +13,17 @@ struct ARM {
#include "instructions-thumb.hpp"
#include "disassembler.hpp"
virtual void step(unsigned clocks) = 0;
virtual void bus_idle(uint32 addr) = 0;
virtual uint32 bus_read(uint32 addr, uint32 size) = 0;
virtual void bus_write(uint32 addr, uint32 size, uint32 word) = 0;
void power();
void exec();
void idle();
uint32 read(uint32 addr, uint32 size);
uint32 load(uint32 addr, uint32 size);
void write(uint32 addr, uint32 size, uint32 word);
void store(uint32 addr, uint32 size, uint32 word);
void vector(uint32 addr, Processor::Mode mode);
bool condition(uint4 condition);
@ -26,10 +31,10 @@ struct ARM {
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 lsl(uint32 source, uint8 shift);
uint32 lsr(uint32 source, uint8 shift);
uint32 asr(uint32 source, uint8 shift);
uint32 ror(uint32 source, uint8 shift);
uint32 rrx(uint32 source);
void serialize(serializer&);

View File

@ -5,6 +5,7 @@ void ARM::arm_step() {
pipeline.reload = false;
r(15).data &= ~3;
sequential() = false;
pipeline.fetch.address = r(15) & ~3;
pipeline.fetch.instruction = read(pipeline.fetch.address, Word);
@ -195,8 +196,8 @@ void ARM::arm_op_memory_swap() {
uint4 d = instruction() >> 12;
uint4 m = instruction();
uint32 word = read(r(n), byte ? Byte : Word);
write(r(n), byte ? Byte : Word, r(m));
uint32 word = load(r(n), byte ? Byte : Word);
store(r(n), byte ? Byte : Word, r(m));
r(d) = word;
}
@ -215,7 +216,7 @@ void ARM::arm_op_move_half_register() {
uint1 pre = instruction() >> 24;
uint1 up = instruction() >> 23;
uint1 writeback = instruction() >> 21;
uint1 load = instruction() >> 20;
uint1 l = instruction() >> 20;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint4 m = instruction();
@ -224,8 +225,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) = read(rn, Half);
if(load == 0) write(rn, Half, r(d));
if(l == 1) r(d) = load(rn, Half);
if(l == 0) store(rn, Half, r(d));
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback == 1) r(n) = rn;
@ -247,7 +248,7 @@ void ARM::arm_op_move_half_immediate() {
uint1 pre = instruction() >> 24;
uint1 up = instruction() >> 23;
uint1 writeback = instruction() >> 21;
uint1 load = instruction() >> 20;
uint1 l = instruction() >> 20;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint4 ih = instruction() >> 8;
@ -257,8 +258,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) = read(rn, Half);
if(load == 0) write(rn, Half, r(d));
if(l == 1) r(d) = load(rn, Half);
if(l == 0) store(rn, Half, r(d));
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
if(pre == 0 || writeback == 1) r(n) = rn;
@ -288,7 +289,7 @@ void ARM::arm_op_load_register() {
uint32 rm = r(m);
if(pre == 1) rn = up ? rn + rm : rn - rm;
uint32 word = read(rn, half ? Half : Byte);
uint32 word = load(rn, half ? Half : Byte);
r(d) = half ? (int16)word : (int8)word;
if(pre == 0) rn = up ? rn + rm : rn - rm;
@ -321,7 +322,7 @@ void ARM::arm_op_load_immediate() {
uint8 immediate = (ih << 4) + (il << 0);
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
uint32 word = read(rn, half ? Half : Byte);
uint32 word = load(rn, half ? Half : Byte);
r(d) = half ? (int16)word : (int8)word;
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
@ -486,7 +487,7 @@ void ARM::arm_op_move_immediate_offset() {
uint1 up = instruction() >> 23;
uint1 byte = instruction() >> 22;
uint1 writeback = instruction() >> 21;
uint1 load = instruction() >> 20;
uint1 l = instruction() >> 20;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint12 rm = instruction();
@ -495,8 +496,8 @@ void ARM::arm_op_move_immediate_offset() {
auto &rd = r(d);
if(pre == 1) rn = up ? rn + rm : rn - rm;
if(load == 1) rd = read(rn, byte ? Byte : Word);
if(load == 0) write(rn, byte ? Byte : Word, rd);
if(l == 1) rd = load(rn, byte ? Byte : Word);
if(l == 0) store(rn, byte ? Byte : Word, rd);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback == 1) r(n) = rn;
@ -521,7 +522,7 @@ void ARM::arm_op_move_register_offset() {
uint1 up = instruction() >> 23;
uint1 byte = instruction() >> 22;
uint1 writeback = instruction() >> 21;
uint1 load = instruction() >> 20;
uint1 l = instruction() >> 20;
uint4 n = instruction() >> 16;
uint4 d = instruction() >> 12;
uint5 immediate = instruction() >> 7;
@ -540,8 +541,8 @@ void ARM::arm_op_move_register_offset() {
if(mode == 3) rm = rs ? ror(rm, rs) : rrx(rm);
if(pre == 1) rn = up ? rn + rm : rn - rm;
if(load == 1) rd = read(rn, byte ? Byte : Word);
if(load == 0) write(rn, byte ? Byte : Word, rd);
if(l == 1) rd = load(rn, byte ? Byte : Word);
if(l == 0) store(rn, byte ? Byte : Word, rd);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback == 1) r(n) = rn;
@ -562,7 +563,7 @@ void ARM::arm_op_move_multiple() {
uint1 up = instruction() >> 23;
uint1 s = instruction() >> 22;
uint1 writeback = instruction() >> 21;
uint1 load = instruction() >> 20;
uint1 l = instruction() >> 20;
uint4 n = instruction() >> 16;
uint16 list = instruction();
@ -574,25 +575,29 @@ void ARM::arm_op_move_multiple() {
Processor::Mode pmode = mode();
bool usr = false;
if(s && load == 1 && (list & 0x8000) == 0) usr = true;
if(s && load == 0) usr = true;
if(s && l == 1 && (list & 0x8000) == 0) usr = true;
if(s && l == 0) usr = true;
if(usr) processor.setMode(Processor::Mode::USR);
for(unsigned n = 0; n < 16; n++) {
if(list & (1 << n)) {
if(load == 1) r(n) = read(rn, Word);
if(load == 0) write(rn, Word, r(n));
sequential() = false;
for(unsigned m = 0; m < 16; m++) {
if(list & (1 << m)) {
if(l == 1) r(m) = read(rn, Word);
if(l == 0) write(rn, Word, r(m));
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(l == 1) {
idle();
if(s && (list & 0x8000)) {
if(mode() != Processor::Mode::USR && mode() != Processor::Mode::SYS) {
cpsr() = spsr();
processor.setMode((Processor::Mode)cpsr().m);
}
}
}

View File

@ -5,6 +5,7 @@ void ARM::thumb_step() {
pipeline.reload = false;
r(15).data &= ~1;
sequential() = false;
pipeline.fetch.address = r(15) & ~1;
pipeline.fetch.instruction = read(pipeline.fetch.address, Half);
@ -62,12 +63,12 @@ void ARM::thumb_opcode(uint4 opcode, uint4 d, uint4 m) {
switch(opcode) {
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 2: r(d) = bit(lsl(r(d), r(m))); break; //LSL
case 3: r(d) = bit(lsr(r(d), r(m))); break; //LSR
case 4: r(d) = bit(asr(r(d), r(m))); 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 7: r(d) = bit(ror(r(d), r(m))); 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
@ -128,9 +129,9 @@ void ARM::thumb_op_shift_immediate() {
uint3 d = instruction() >> 0;
switch(opcode) {
case 0: r(d) = lsl(r(m), immediate); break;
case 1: r(d) = lsr(r(m), immediate == 0 ? 32u : (unsigned)immediate); break;
case 2: r(d) = asr(r(m), immediate == 0 ? 32u : (unsigned)immediate); break;
case 0: r(d) = bit(lsl(r(m), immediate)); break;
case 1: r(d) = bit(lsr(r(m), immediate == 0 ? 32u : (unsigned)immediate)); break;
case 2: r(d) = bit(asr(r(m), immediate == 0 ? 32u : (unsigned)immediate)); break;
}
}
@ -203,7 +204,7 @@ void ARM::thumb_op_load_literal() {
uint8 displacement = instruction();
unsigned rm = (r(15) & ~3) + displacement * 4;
r(d) = read(rm, Word);
r(d) = load(rm, Word);
}
//(ld(r,s),str){b,h} rd,[rn,rm]
@ -219,14 +220,14 @@ void ARM::thumb_op_move_register_offset() {
uint3 d = instruction() >> 0;
switch(opcode) {
case 0: write(r(n) + r(m), Word, r(d)); break; //STR
case 1: write(r(n) + r(m), Half, r(d)); break; //STRH
case 2: write(r(n) + r(m), Byte, r(d)); break; //STRB
case 3: r(d) = (int8)read(r(n) + r(m), Byte); break; //LDSB
case 4: r(d) = read(r(n) + r(m), Word); break; //LDR
case 5: r(d) = read(r(n) + r(m), Half); break; //LDRH
case 6: r(d) = read(r(n) + r(m), Byte); break; //LDRB
case 7: r(d) = (int16)read(r(n) + r(m), Half); break; //LDSH
case 0: store(r(n) + r(m), Word, r(d)); break; //STR
case 1: store(r(n) + r(m), Half, r(d)); break; //STRH
case 2: store(r(n) + r(m), Byte, r(d)); break; //STRB
case 3: r(d) = (int8)load(r(n) + r(m), Byte); break; //LDSB
case 4: r(d) = load(r(n) + r(m), Word); break; //LDR
case 5: r(d) = load(r(n) + r(m), Half); break; //LDRH
case 6: r(d) = load(r(n) + r(m), Byte); break; //LDRB
case 7: r(d) = (int16)load(r(n) + r(m), Half); break; //LDSH
}
}
@ -237,13 +238,13 @@ void ARM::thumb_op_move_register_offset() {
//n = rn
//d = rd
void ARM::thumb_op_move_word_immediate() {
uint1 load = instruction() >> 11;
uint1 l = instruction() >> 11;
uint5 offset = instruction() >> 6;
uint3 n = instruction() >> 3;
uint3 d = instruction() >> 0;
if(load == 1) r(d) = read(r(n) + offset * 4, Word);
if(load == 0) write(r(n) + offset * 4, Word, r(d));
if(l == 1) r(d) = load(r(n) + offset * 4, Word);
if(l == 0) store(r(n) + offset * 4, Word, r(d));
}
//(ldr,str)b rd,[rn,#offset]
@ -253,13 +254,13 @@ void ARM::thumb_op_move_word_immediate() {
//n = rn
//d = rd
void ARM::thumb_op_move_byte_immediate() {
uint1 load = instruction() >> 11;
uint1 l = instruction() >> 11;
uint5 offset = instruction() >> 6;
uint3 n = instruction() >> 3;
uint3 d = instruction() >> 0;
if(load == 1) r(d) = read(r(n) + offset, Byte);
if(load == 0) write(r(n) + offset, Byte, r(d));
if(l == 1) r(d) = load(r(n) + offset, Byte);
if(l == 0) store(r(n) + offset, Byte, r(d));
}
//(ldr,str)h rd,[rn,#offset]
@ -269,27 +270,27 @@ void ARM::thumb_op_move_byte_immediate() {
//n = rn
//d = rd
void ARM::thumb_op_move_half_immediate() {
uint1 load = instruction() >> 11;
uint1 l = instruction() >> 11;
uint5 offset = instruction() >> 6;
uint3 n = instruction() >> 3;
uint3 d = instruction() >> 0;
if(load == 1) r(d) = read(r(n) + offset * 2, Half);
if(load == 0) write(r(n) + offset * 2, Half, r(d));
if(l == 1) r(d) = load(r(n) + offset * 2, Half);
if(l == 0) store(r(n) + offset * 2, Half, r(d));
}
//(ldr,str) rd,[sp,#immediate]
//1001 oddd iiii iiii
//o = opcode
//l = load
//d = rd
//i = immediate
void ARM::thumb_op_move_stack() {
uint1 opcode = instruction() >> 11;
uint1 l = instruction() >> 11;
uint3 d = instruction() >> 8;
uint8 immediate = instruction();
if(opcode == 0) write(r(13) + immediate * 4, Word, r(d));
if(opcode == 1) r(d) = read(r(13) + immediate * 4, Word);
if(l == 1) r(d) = load(r(13) + immediate * 4, Word);
if(l == 0) store(r(13) + immediate * 4, Word, r(d));
}
//add rd,{pc,sp},#immediate
@ -325,31 +326,33 @@ void ARM::thumb_op_adjust_stack() {
//r = push lr -or- pop pc
//l = register list
void ARM::thumb_op_stack_multiple() {
uint1 load = instruction() >> 11;
uint1 l = instruction() >> 11;
uint1 branch = instruction() >> 8;
uint8 list = instruction();
uint32 sp = 0;
if(load == 1) sp = r(13);
if(load == 0) sp = r(13) - (bit::count(list) + branch) * 4;
if(l == 1) sp = r(13);
if(l == 0) sp = r(13) - (bit::count(list) + branch) * 4;
for(unsigned l = 0; l < 8; l++) {
if(list & (1 << l)) {
if(load == 1) r(l) = read(sp, Word); //POP
if(load == 0) write(sp, Word, r(l)); //PUSH
sequential() = false;
for(unsigned m = 0; m < 8; m++) {
if(list & (1 << m)) {
if(l == 1) r(m) = read(sp, Word); //POP
if(l == 0) write(sp, Word, r(m)); //PUSH
sp += 4;
}
}
if(branch) {
//note: ARMv5+ POP sets cpsr().t
if(load == 1) r(15) = read(sp, Word); //POP
if(load == 0) write(sp, Word, r(14)); //PUSH
if(l == 1) r(15) = read(sp, Word); //POP
if(l == 0) write(sp, Word, r(14)); //PUSH
sp += 4;
}
if(load == 1) r(13) += (bit::count(list) + branch) * 4;
if(load == 0) r(13) -= (bit::count(list) + branch) * 4;
if(l == 1) idle();
if(l == 1) r(13) += (bit::count(list) + branch) * 4;
if(l == 0) r(13) -= (bit::count(list) + branch) * 4;
}
//(ldmia,stmia) rn!,{r...}
@ -358,17 +361,20 @@ void ARM::thumb_op_stack_multiple() {
//n = rn
//l = register list
void ARM::thumb_op_move_multiple() {
uint1 load = instruction() >> 11;
uint1 l = instruction() >> 11;
uint3 n = instruction() >> 8;
uint8 list = instruction();
for(unsigned l = 0; l < 8; l++) {
if(list & (1 << l)) {
if(load == 1) r(l) = read(r(n), Word); //LDMIA
if(load == 0) write(r(n), Word, r(l)); //STMIA
sequential() = false;
for(unsigned m = 0; m < 8; m++) {
if(list & (1 << m)) {
if(l == 1) r(m) = read(r(n), Word); //LDMIA
if(l == 0) write(r(n), Word, r(m)); //STMIA
r(n) += 4;
}
}
if(l == 1) idle();
}
//swi #immediate

View File

@ -11,6 +11,7 @@ void ARM::Processor::power() {
pc = 0;
carryout = false;
sequential = false;
irqline = false;
cpsr = 0;

View File

@ -104,6 +104,7 @@ struct Processor {
GPR pc;
PSR cpsr;
bool carryout;
bool sequential;
bool irqline;
GPR *r[16];
@ -123,6 +124,7 @@ 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 bool& sequential() { return processor.sequential; }
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; }

View File

@ -12,6 +12,7 @@ struct ArmDSP : Processor::ARM, public Coprocessor {
void enter();
void step(unsigned clocks);
void bus_idle(uint32 addr);
uint32 bus_read(uint32 addr, uint32 size);
void bus_write(uint32 addr, uint32 size, uint32 word);

View File

@ -1,6 +1,12 @@
#ifdef ARMDSP_CPP
void ArmDSP::bus_idle(uint32 addr) {
step(1);
}
uint32 ArmDSP::bus_read(uint32 addr, uint32 size) {
step(1);
static auto memory = [&](const uint8 *memory, uint32 addr, uint32 size) {
memory += addr & ~3;
return (memory[0] << 0) | (memory[1] << 8) | (memory[2] << 16) | (memory[3] << 24);
@ -34,6 +40,8 @@ uint32 ArmDSP::bus_read(uint32 addr, uint32 size) {
}
void ArmDSP::bus_write(uint32 addr, uint32 size, uint32 word) {
step(1);
static auto memory = [](uint8 *memory, uint32 addr, uint32 size, uint32 word) {
switch(size) {
case Word:

View File

@ -69,18 +69,23 @@ else
endif
install:
ifeq ($(platform),x)
install -D -m 755 out/$(name) $(DESTDIR)$(prefix)/bin/$(name)
ifeq ($(USER),root)
@echo Please do not run make install as root.
@echo The installer needs to know your home directory to install important files.
else ifeq ($(platform),x)
sudo install -D -m 755 out/$(name) $(DESTDIR)$(prefix)/bin/$(name)
sudo install -D -m 644 data/$(name).png $(DESTDIR)$(prefix)/share/pixmaps/$(name).png
sudo install -D -m 644 data/$(name).desktop $(DESTDIR)$(prefix)/share/applications/$(name).desktop
mkdir -p ~/.config/$(name)
install -D -m 644 data/$(name).png $(DESTDIR)$(prefix)/share/pixmaps/$(name).png
install -D -m 644 data/$(name).desktop $(DESTDIR)$(prefix)/share/applications/$(name).desktop
cp data/cheats.xml ~/.config/$(name)/cheats.xml
chmod 777 ~/.config/$(name) ~/.config/$(name)/cheats.xml
cp -R data/GBA.system ~/.config/$(name)
chmod -R 777 ~/.config/$(name)
endif
uninstall:
ifeq ($(platform),x)
rm $(DESTDIR)$(prefix)/bin/$(name)
rm $(DESTDIR)$(prefix)/share/pixmaps/$(name).png
rm $(DESTDIR)$(prefix)/share/applications/$(name).desktop
sudo rm $(DESTDIR)$(prefix)/bin/$(name)
sudo rm $(DESTDIR)$(prefix)/share/pixmaps/$(name).png
sudo rm $(DESTDIR)$(prefix)/share/applications/$(name).desktop
endif

View File

@ -1,4 +1,25 @@
void InterfaceGBA::initialize() {
string filename = application->path("GBA.system/manifest.xml");
string markup;
markup.readfile(filename);
XML::Document document(markup);
if(document["system"]["bios"].exists()) {
auto &bios = document["system"]["bios"];
string firmware = bios["firmware"].data;
string hash = bios["sha256"].data;
uint8_t *data;
unsigned size;
if(file::read({dir(filename),firmware}, data, size) == true) {
if(nall::sha256(data, size) == hash) {
GBA::bios.load(data, size);
} else {
MessageWindow::information(Window::None, "Warning: GBA BIOS SHA256 sum is incorrect.");
}
}
}
GBA::interface = this;
GBA::system.init();
}
@ -10,42 +31,27 @@ bool InterfaceGBA::cartridgeLoaded() {
bool InterfaceGBA::loadCartridge(const string &filename) {
interface->unloadCartridge();
uint8_t *biosdata;
unsigned biossize;
uint8_t *cartdata;
unsigned cartsize;
uint8_t *data;
unsigned size;
if(filename.endswith("/")) {
if(file::exists({filename, "bios.rom"}) == false) {
message("Error: Game Boy Advance BIOS (bios.rom) not found.");
return false;
}
if(file::read({filename, "bios.rom"}, biosdata, biossize) == false) return false;
if(file::read({filename, "program.rom"}, cartdata, cartsize) == false) return false;
if(file::read({filename, "program.rom"}, data, size) == false) return false;
interface->base = {true, filename};
} else {
if(file::exists({dir(filename), "gbabios.rom"}) == false) {
message("Error: Game Boy Advance BIOS (gbabios.rom) not found.");
return false;
}
if(file::read({dir(filename), "gbabios.rom"}, biosdata, biossize) == false) return false;
if(file::read(filename, cartdata, cartsize) == false) return false;
if(file::read(filename, data, size) == false) return false;
interface->base = {false, filename};
}
interface->game = interface->base;
interface->cartridgeTitle = interface->base.title();
interface->applyPatch(interface->base, cartdata, cartsize);
interface->applyPatch(interface->base, data, size);
string markup;
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
GBA::bios.load(biosdata, biossize);
GBA::cartridge.load(markup, cartdata, cartsize);
GBA::cartridge.load(markup, data, size);
GBA::system.power();
delete[] biosdata;
delete[] cartdata;
delete[] data;
GBA::video.generate(GBA::Video::Format::RGB30);
interface->loadCartridge(::Interface::Mode::GBA);

View File

@ -15,8 +15,6 @@ AdvancedSettings::AdvancedSettings() {
focusPolicy[2].setText("Pause emulation");
RadioBox::group(focusPolicy[0], focusPolicy[1], focusPolicy[2]);
focusPolicy[config->input.focusPolicy].setChecked();
aboutLabel.setFont(application->boldFont);
aboutLabel.setText("bsnes author: byuu license: GPLv3 website: byuu.org");
lstring list;
@ -55,8 +53,6 @@ AdvancedSettings::AdvancedSettings() {
focusPolicyLayout.append(focusPolicy[0], { ~0, 0 }, 5);
focusPolicyLayout.append(focusPolicy[1], { ~0, 0 }, 5);
focusPolicyLayout.append(focusPolicy[2], { ~0, 0 }, 0);
append(spacer, { ~0, ~0 }, 0);
append(aboutLabel, { ~0, 0 }, 0);
videoDriver.onChange = [&] {
lstring list;

View File

@ -11,8 +11,6 @@ struct AdvancedSettings : SettingsLayout {
Label focusPolicyLabel;
HorizontalLayout focusPolicyLayout;
RadioBox focusPolicy[3];
Widget spacer;
Label aboutLabel;
AdvancedSettings();
};