mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
28885db586
commit
1c18812f47
|
@ -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>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<system type="GBA">
|
||||
<bios firmware="bios.rom" sha256="fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570"/>
|
||||
</system>
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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&);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -11,6 +11,7 @@ void ARM::Processor::power() {
|
|||
pc = 0;
|
||||
|
||||
carryout = false;
|
||||
sequential = false;
|
||||
irqline = false;
|
||||
|
||||
cpsr = 0;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -11,8 +11,6 @@ struct AdvancedSettings : SettingsLayout {
|
|||
Label focusPolicyLabel;
|
||||
HorizontalLayout focusPolicyLayout;
|
||||
RadioBox focusPolicy[3];
|
||||
Widget spacer;
|
||||
Label aboutLabel;
|
||||
|
||||
AdvancedSettings();
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue