diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index 06f92f31..2c04c072 100755 --- a/bsnes/base/base.hpp +++ b/bsnes/base/base.hpp @@ -1,7 +1,7 @@ #ifndef BASE_HPP #define BASE_HPP -static const char Version[] = "087.23"; +static const char Version[] = "087.25"; #include #include diff --git a/bsnes/data/GBA.system/manifest.xml b/bsnes/data/GBA.system/manifest.xml new file mode 100755 index 00000000..f6b52ae0 --- /dev/null +++ b/bsnes/data/GBA.system/manifest.xml @@ -0,0 +1,4 @@ + + + + diff --git a/bsnes/gba/cpu/cpu.cpp b/bsnes/gba/cpu/cpu.cpp index 47294b90..3a370207 100755 --- a/bsnes/gba/cpu/cpu.cpp +++ b/bsnes/gba/cpu/cpu.cpp @@ -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); diff --git a/bsnes/gba/cpu/cpu.hpp b/bsnes/gba/cpu/cpu.hpp index 7e5ea11a..d2c2cc6e 100755 --- a/bsnes/gba/cpu/cpu.hpp +++ b/bsnes/gba/cpu/cpu.hpp @@ -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); diff --git a/bsnes/gba/cpu/registers.cpp b/bsnes/gba/cpu/registers.cpp index 600588a5..43ce04c2 100755 --- a/bsnes/gba/cpu/registers.cpp +++ b/bsnes/gba/cpu/registers.cpp @@ -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(); } diff --git a/bsnes/gba/cpu/registers.hpp b/bsnes/gba/cpu/registers.hpp index bf439a82..98b5cda8 100755 --- a/bsnes/gba/cpu/registers.hpp +++ b/bsnes/gba/cpu/registers.hpp @@ -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; diff --git a/bsnes/gba/memory/memory.cpp b/bsnes/gba/memory/memory.cpp index 9e4a3c8a..b4c02f4e 100755 --- a/bsnes/gba/memory/memory.cpp +++ b/bsnes/gba/memory/memory.cpp @@ -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; } } diff --git a/bsnes/gba/memory/memory.hpp b/bsnes/gba/memory/memory.hpp index 5c9adf70..743b0caa 100755 --- a/bsnes/gba/memory/memory.hpp +++ b/bsnes/gba/memory/memory.hpp @@ -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(); diff --git a/bsnes/gba/ppu/object.cpp b/bsnes/gba/ppu/object.cpp index 82e5b376..ca2d2ae6 100755 --- a/bsnes/gba/ppu/object.cpp +++ b/bsnes/gba/ppu/object.cpp @@ -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); diff --git a/bsnes/processor/arm/algorithms.cpp b/bsnes/processor/arm/algorithms.cpp index 42b5c1ae..8eb5d6bb 100755 --- a/bsnes/processor/arm/algorithms.cpp +++ b/bsnes/processor/arm/algorithms.cpp @@ -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; } diff --git a/bsnes/processor/arm/arm.cpp b/bsnes/processor/arm/arm.cpp index 5f70e0b5..a3734dc3 100755 --- a/bsnes/processor/arm/arm.cpp +++ b/bsnes/processor/arm/arm.cpp @@ -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; diff --git a/bsnes/processor/arm/arm.hpp b/bsnes/processor/arm/arm.hpp index 0b2e0e42..38b58d61 100755 --- a/bsnes/processor/arm/arm.hpp +++ b/bsnes/processor/arm/arm.hpp @@ -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&); diff --git a/bsnes/processor/arm/instructions-arm.cpp b/bsnes/processor/arm/instructions-arm.cpp index fca10cc1..b4369aef 100755 --- a/bsnes/processor/arm/instructions-arm.cpp +++ b/bsnes/processor/arm/instructions-arm.cpp @@ -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); + } } } diff --git a/bsnes/processor/arm/instructions-thumb.cpp b/bsnes/processor/arm/instructions-thumb.cpp index c56ff088..b795d4cd 100755 --- a/bsnes/processor/arm/instructions-thumb.cpp +++ b/bsnes/processor/arm/instructions-thumb.cpp @@ -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 diff --git a/bsnes/processor/arm/registers.cpp b/bsnes/processor/arm/registers.cpp index 9292be3f..e6a3539d 100755 --- a/bsnes/processor/arm/registers.cpp +++ b/bsnes/processor/arm/registers.cpp @@ -11,6 +11,7 @@ void ARM::Processor::power() { pc = 0; carryout = false; + sequential = false; irqline = false; cpsr = 0; diff --git a/bsnes/processor/arm/registers.hpp b/bsnes/processor/arm/registers.hpp index c5f355b8..6c1fa426 100755 --- a/bsnes/processor/arm/registers.hpp +++ b/bsnes/processor/arm/registers.hpp @@ -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; } diff --git a/bsnes/snes/chip/armdsp/armdsp.hpp b/bsnes/snes/chip/armdsp/armdsp.hpp index e6bad18a..385cfc47 100755 --- a/bsnes/snes/chip/armdsp/armdsp.hpp +++ b/bsnes/snes/chip/armdsp/armdsp.hpp @@ -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); diff --git a/bsnes/snes/chip/armdsp/memory.cpp b/bsnes/snes/chip/armdsp/memory.cpp index f1e5ce11..29af732c 100755 --- a/bsnes/snes/chip/armdsp/memory.cpp +++ b/bsnes/snes/chip/armdsp/memory.cpp @@ -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: diff --git a/bsnes/target-ui/Makefile b/bsnes/target-ui/Makefile index 285b9f39..34fc9ab9 100755 --- a/bsnes/target-ui/Makefile +++ b/bsnes/target-ui/Makefile @@ -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 diff --git a/bsnes/target-ui/interface/gba/gba.cpp b/bsnes/target-ui/interface/gba/gba.cpp index 11ae4c98..5f590113 100755 --- a/bsnes/target-ui/interface/gba/gba.cpp +++ b/bsnes/target-ui/interface/gba/gba.cpp @@ -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); diff --git a/bsnes/target-ui/settings/advanced.cpp b/bsnes/target-ui/settings/advanced.cpp index f3c0b4c5..cf43888e 100755 --- a/bsnes/target-ui/settings/advanced.cpp +++ b/bsnes/target-ui/settings/advanced.cpp @@ -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; diff --git a/bsnes/target-ui/settings/advanced.hpp b/bsnes/target-ui/settings/advanced.hpp index 89e0432e..860527d8 100755 --- a/bsnes/target-ui/settings/advanced.hpp +++ b/bsnes/target-ui/settings/advanced.hpp @@ -11,8 +11,6 @@ struct AdvancedSettings : SettingsLayout { Label focusPolicyLabel; HorizontalLayout focusPolicyLayout; RadioBox focusPolicy[3]; - Widget spacer; - Label aboutLabel; AdvancedSettings(); };