mirror of https://github.com/bsnes-emu/bsnes.git
Update to v094r34 release.
byuu says: Fixes SuperFX fmult, lmult timings; rambr, bramr and clsr assignment masking. Implements true GBA ROM prefetch (buggy, lower test score, but runs Mario & Luigi without crashing on battles anymore.)
This commit is contained in:
parent
4c9266d18f
commit
7ff7f64482
|
@ -8,7 +8,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "094.33";
|
static const string Version = "094.34";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
@ -33,7 +33,7 @@ template<typename R, typename... P> struct hook<R (P...)> {
|
||||||
|
|
||||||
auto operator()(P... p) const -> R {
|
auto operator()(P... p) const -> R {
|
||||||
#if defined(DEBUGGER)
|
#if defined(DEBUGGER)
|
||||||
if(callback) return callback(std::forward<P>(p)...);
|
if(callback) return callback(forward<P>(p)...);
|
||||||
#endif
|
#endif
|
||||||
return R();
|
return R();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ struct Interface {
|
||||||
unsigned id;
|
unsigned id;
|
||||||
unsigned type; //0 = digital, 1 = analog (relative), 2 = rumble
|
unsigned type; //0 = digital, 1 = analog (relative), 2 = rumble
|
||||||
string name;
|
string name;
|
||||||
uintptr_t guid;
|
uintptr_t guid; //user data field
|
||||||
};
|
};
|
||||||
vector<Input> input;
|
vector<Input> input;
|
||||||
vector<unsigned> order;
|
vector<unsigned> order;
|
||||||
|
@ -57,7 +57,6 @@ struct Interface {
|
||||||
virtual auto inputRumble(unsigned, unsigned, unsigned, bool) -> void {}
|
virtual auto inputRumble(unsigned, unsigned, unsigned, bool) -> void {}
|
||||||
virtual auto dipSettings(const Markup::Node&) -> unsigned { return 0; }
|
virtual auto dipSettings(const Markup::Node&) -> unsigned { return 0; }
|
||||||
virtual auto path(unsigned) -> string { return ""; }
|
virtual auto path(unsigned) -> string { return ""; }
|
||||||
virtual auto server() -> string { return ""; }
|
|
||||||
virtual auto notify(string text) -> void { print(text, "\n"); }
|
virtual auto notify(string text) -> void { print(text, "\n"); }
|
||||||
};
|
};
|
||||||
Bind* bind = nullptr;
|
Bind* bind = nullptr;
|
||||||
|
@ -73,7 +72,6 @@ struct Interface {
|
||||||
auto inputRumble(unsigned port, unsigned device, unsigned input, bool enable) -> void { return bind->inputRumble(port, device, input, enable); }
|
auto inputRumble(unsigned port, unsigned device, unsigned input, bool enable) -> void { return bind->inputRumble(port, device, input, enable); }
|
||||||
auto dipSettings(const Markup::Node& node) -> unsigned { return bind->dipSettings(node); }
|
auto dipSettings(const Markup::Node& node) -> unsigned { return bind->dipSettings(node); }
|
||||||
auto path(unsigned group) -> string { return bind->path(group); }
|
auto path(unsigned group) -> string { return bind->path(group); }
|
||||||
auto server() -> string { return bind->server(); }
|
|
||||||
template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); }
|
template<typename... P> auto notify(P&&... p) -> void { return bind->notify({forward<P>(p)...}); }
|
||||||
|
|
||||||
//information
|
//information
|
||||||
|
|
107
gba/cpu/cpu.cpp
107
gba/cpu/cpu.cpp
|
@ -63,6 +63,72 @@ auto CPU::step(unsigned clocks) -> void {
|
||||||
sync_step(clocks);
|
sync_step(clocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto CPU::bus_idle(uint32 addr) -> void {
|
||||||
|
step(1);
|
||||||
|
prefetch_step(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::bus_read(uint32 addr, uint32 size, bool mode) -> uint32 {
|
||||||
|
unsigned wait = bus.wait(addr, size, mode);
|
||||||
|
|
||||||
|
if(addr < 0x0800'0000) {
|
||||||
|
unsigned word = bus.read(addr, size);
|
||||||
|
step(wait);
|
||||||
|
prefetch_step(wait);
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr < 0x0e00'0000) {
|
||||||
|
if(regs.wait.control.prefetch) {
|
||||||
|
if(mode == Nonsequential) prefetch_start(addr);
|
||||||
|
unsigned word = prefetch_take();
|
||||||
|
if(size == Byte) word = (addr & 1) ? (word >> 8) : (word & 0xff);
|
||||||
|
if(size == Word) word |= prefetch_take() << 16;
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned word = cartridge.read(addr, size);
|
||||||
|
step(wait);
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr < 0x1000'0000) {
|
||||||
|
prefetch_stall();
|
||||||
|
unsigned word = bus.read(addr, size);
|
||||||
|
step(wait);
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
step(wait);
|
||||||
|
prefetch_step(wait);
|
||||||
|
return 0x0000'0000; //open bus?
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::bus_write(uint32 addr, uint32 size, bool mode, uint32 word) -> void {
|
||||||
|
unsigned wait = bus.wait(addr, size, mode);
|
||||||
|
|
||||||
|
if(addr < 0x0800'0000) {
|
||||||
|
step(wait);
|
||||||
|
prefetch_step(wait);
|
||||||
|
return bus.write(addr, size, word);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr < 0x0e00'0000) {
|
||||||
|
prefetch_stall();
|
||||||
|
step(wait);
|
||||||
|
return bus.write(addr, size, word);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(addr < 0x1000'0000) {
|
||||||
|
prefetch_stall();
|
||||||
|
step(wait);
|
||||||
|
return bus.write(addr, size, word);
|
||||||
|
}
|
||||||
|
|
||||||
|
step(wait);
|
||||||
|
prefetch_step(wait);
|
||||||
|
}
|
||||||
|
|
||||||
auto CPU::sync_step(unsigned clocks) -> void {
|
auto CPU::sync_step(unsigned clocks) -> void {
|
||||||
ppu.clock -= clocks;
|
ppu.clock -= clocks;
|
||||||
if(ppu.clock < 0) co_switch(ppu.thread);
|
if(ppu.clock < 0) co_switch(ppu.thread);
|
||||||
|
@ -71,43 +137,6 @@ auto CPU::sync_step(unsigned clocks) -> void {
|
||||||
if(apu.clock < 0) co_switch(apu.thread);
|
if(apu.clock < 0) co_switch(apu.thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::bus_idle(uint32 addr) -> void {
|
|
||||||
if(regs.wait.control.prefetch) prefetch_run();
|
|
||||||
step(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPU::bus_read(uint32 addr, uint32 size, bool mode) -> uint32 {
|
|
||||||
if(regs.wait.control.prefetch) {
|
|
||||||
if((addr & 0x0fffffff) >= 0x08000000 && (addr & 0x0fffffff) <= 0x0dffffff) {
|
|
||||||
if(auto word = prefetch_read(addr, size)) {
|
|
||||||
step(1 + (size == Word));
|
|
||||||
return *word;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned wait = bus.wait(addr, size, mode);
|
|
||||||
unsigned word = bus.read(addr, size);
|
|
||||||
step(wait);
|
|
||||||
return word;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPU::bus_load(uint32 addr, uint32 size, bool mode) -> uint32 {
|
|
||||||
if(regs.wait.control.prefetch) prefetch_run();
|
|
||||||
return bus_read(addr, size, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPU::bus_write(uint32 addr, uint32 size, bool mode, uint32 word) -> void {
|
|
||||||
unsigned wait = bus.wait(addr, size, mode);
|
|
||||||
step(wait);
|
|
||||||
bus.write(addr, size, word);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPU::bus_store(uint32 addr, uint32 size, bool mode, uint32 word) -> void {
|
|
||||||
if(regs.wait.control.prefetch) prefetch_run();
|
|
||||||
return bus_write(addr, size, mode, word);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto CPU::keypad_run() -> void {
|
auto CPU::keypad_run() -> void {
|
||||||
if(regs.keypad.control.enable == false) return;
|
if(regs.keypad.control.enable == false) return;
|
||||||
|
|
||||||
|
@ -122,7 +151,7 @@ auto CPU::keypad_run() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::power() -> void {
|
auto CPU::power() -> void {
|
||||||
create(CPU::Enter, 16777216);
|
create(CPU::Enter, 16'777'216);
|
||||||
|
|
||||||
ARM::power();
|
ARM::power();
|
||||||
for(auto n : range( 32 * 1024)) iwram[n] = 0;
|
for(auto n : range( 32 * 1024)) iwram[n] = 0;
|
||||||
|
@ -152,7 +181,7 @@ auto CPU::power() -> void {
|
||||||
regs.postboot = 0;
|
regs.postboot = 0;
|
||||||
regs.mode = Registers::Mode::Normal;
|
regs.mode = Registers::Mode::Normal;
|
||||||
regs.clock = 0;
|
regs.clock = 0;
|
||||||
regs.memory.control = 0x0d000020;
|
regs.memory.control = 0x0d00'0020;
|
||||||
|
|
||||||
pending.dma.vblank = 0;
|
pending.dma.vblank = 0;
|
||||||
pending.dma.hblank = 0;
|
pending.dma.hblank = 0;
|
||||||
|
|
|
@ -12,15 +12,13 @@ struct CPU : Processor::ARM, Thread, MMIO {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
|
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
auto step(unsigned clocks) -> void;
|
|
||||||
|
auto step(unsigned clocks) -> void override;
|
||||||
|
auto bus_idle(uint32 addr) -> void override;
|
||||||
|
auto bus_read(uint32 addr, uint32 size, bool mode) -> uint32 override;
|
||||||
|
auto bus_write(uint32 addr, uint32 size, bool mode, uint32 word) -> void override;
|
||||||
|
|
||||||
auto sync_step(unsigned clocks) -> void;
|
auto sync_step(unsigned clocks) -> void;
|
||||||
|
|
||||||
auto bus_idle(uint32 addr) -> void;
|
|
||||||
auto bus_read(uint32 addr, uint32 size, bool mode) -> uint32;
|
|
||||||
auto bus_load(uint32 addr, uint32 size, bool mode) -> uint32;
|
|
||||||
auto bus_write(uint32 addr, uint32 size, bool mode, uint32 word) -> void;
|
|
||||||
auto bus_store(uint32 addr, uint32 size, bool mode, uint32 word) -> void;
|
|
||||||
|
|
||||||
auto keypad_run() -> void;
|
auto keypad_run() -> void;
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,43 @@
|
||||||
auto CPU::prefetch_run() -> void {
|
auto CPU::prefetch_stall() -> void {
|
||||||
if(prefetch.slots == 8) return;
|
prefetch.stalled = true;
|
||||||
prefetch.slots++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::prefetch_read(uint32 addr, uint32 size) -> maybe<uint32> {
|
auto CPU::prefetch_start(uint32 addr) -> void {
|
||||||
if(prefetch.slots >= (size == Word ? 2 : 1)) {
|
prefetch.stalled = false;
|
||||||
prefetch.slots -= (size == Word ? 2 : 1);
|
prefetch.slots = 0;
|
||||||
return cartridge.read(addr, size);
|
prefetch.input = 0;
|
||||||
|
prefetch.output = 0;
|
||||||
|
prefetch.addr = addr;
|
||||||
|
prefetch.wait = bus.wait(addr, Half, Nonsequential);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::prefetch_step(unsigned clocks) -> void {
|
||||||
|
if(!regs.wait.control.prefetch || prefetch.stalled) return;
|
||||||
|
|
||||||
|
prefetch.wait -= clocks;
|
||||||
|
while(prefetch.wait <= 0) {
|
||||||
|
if(prefetch.slots < 8) {
|
||||||
|
prefetch.slot[prefetch.output++] = cartridge.read(prefetch.addr, Half);
|
||||||
|
prefetch.slots++;
|
||||||
|
prefetch.addr += 2;
|
||||||
|
}
|
||||||
|
prefetch.wait += bus.wait(prefetch.addr, Half, Sequential);
|
||||||
}
|
}
|
||||||
prefetch.slots = 0;
|
}
|
||||||
return nothing;
|
|
||||||
|
auto CPU::prefetch_wait() -> void {
|
||||||
|
step(prefetch.wait);
|
||||||
|
prefetch_step(prefetch.wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::prefetch_take() -> uint16 {
|
auto CPU::prefetch_take() -> uint16 {
|
||||||
return 0;
|
if(prefetch.slots) {
|
||||||
|
step(1);
|
||||||
|
prefetch_step(1);
|
||||||
|
} else {
|
||||||
|
prefetch_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
prefetch.slots--;
|
||||||
|
return prefetch.slot[prefetch.input++];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
struct Prefetch {
|
struct Prefetch {
|
||||||
struct Slot {
|
uint16 slot[8] = {0};
|
||||||
uint32 addr;
|
uint3 input = 0;
|
||||||
uint16 half;
|
uint3 output = 0;
|
||||||
} slot[8];
|
|
||||||
|
|
||||||
|
bool stalled = true;
|
||||||
unsigned slots = 0;
|
unsigned slots = 0;
|
||||||
|
signed wait = 0;
|
||||||
uint32 addr = 0;
|
uint32 addr = 0;
|
||||||
} prefetch;
|
} prefetch;
|
||||||
|
|
||||||
auto prefetch_run() -> void;
|
auto prefetch_stall() -> void;
|
||||||
auto prefetch_read(uint32 addr, uint32 size) -> maybe<uint32>;
|
auto prefetch_start(uint32 addr) -> void;
|
||||||
|
auto prefetch_step(unsigned clocks) -> void;
|
||||||
|
auto prefetch_wait() -> void;
|
||||||
auto prefetch_take() -> uint16;
|
auto prefetch_take() -> uint16;
|
||||||
|
|
|
@ -221,6 +221,9 @@ auto CPU::Registers::WaitControl::operator=(uint16 source) -> uint16 {
|
||||||
prefetch = (source >> 14) & 1;
|
prefetch = (source >> 14) & 1;
|
||||||
gametype = (source >> 15) & 1;
|
gametype = (source >> 15) & 1;
|
||||||
swait[3] = nwait[3];
|
swait[3] = nwait[3];
|
||||||
|
|
||||||
|
cpu.prefetch.stalled = true;
|
||||||
|
|
||||||
return operator uint16();
|
return operator uint16();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ auto mMenuRadioItem::setChecked() -> type& {
|
||||||
auto mMenuRadioItem::setGroup(sGroup group) -> type& {
|
auto mMenuRadioItem::setGroup(sGroup group) -> type& {
|
||||||
state.group = group;
|
state.group = group;
|
||||||
signal(setGroup, group);
|
signal(setGroup, group);
|
||||||
|
if(group && group->objects() == 1) setChecked();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ auto mRadioButton::setChecked() -> type& {
|
||||||
auto mRadioButton::setGroup(sGroup group) -> type& {
|
auto mRadioButton::setGroup(sGroup group) -> type& {
|
||||||
state.group = group;
|
state.group = group;
|
||||||
signal(setGroup, group);
|
signal(setGroup, group);
|
||||||
|
if(group && group->objects() == 1) setChecked();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ auto mRadioLabel::setChecked() -> type& {
|
||||||
auto mRadioLabel::setGroup(sGroup group) -> type& {
|
auto mRadioLabel::setGroup(sGroup group) -> type& {
|
||||||
state.group = group;
|
state.group = group;
|
||||||
signal(setGroup, group);
|
signal(setGroup, group);
|
||||||
|
if(group && group->objects() == 1) setChecked();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ auto ARM::read(uint32 addr, uint32 size, bool mode) -> uint32 {
|
||||||
|
|
||||||
auto ARM::load(uint32 addr, uint32 size, bool mode) -> uint32 {
|
auto ARM::load(uint32 addr, uint32 size, bool mode) -> uint32 {
|
||||||
if(processor.nonsequential) processor.nonsequential = false, mode = Nonsequential;
|
if(processor.nonsequential) processor.nonsequential = false, mode = Nonsequential;
|
||||||
uint32 word = bus_load(addr, size, mode);
|
uint32 word = bus_read(addr, size, mode);
|
||||||
|
|
||||||
if(size == Half) { word &= 0xffff; word |= word << 16; }
|
if(size == Half) { word &= 0xffff; word |= word << 16; }
|
||||||
if(size == Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
if(size == Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
||||||
|
@ -63,7 +63,7 @@ auto ARM::store(uint32 addr, uint32 size, bool mode, uint32 word) -> void {
|
||||||
if(size == Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
if(size == Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
||||||
|
|
||||||
if(processor.nonsequential) processor.nonsequential = false, mode = Nonsequential;
|
if(processor.nonsequential) processor.nonsequential = false, mode = Nonsequential;
|
||||||
bus_store(addr, size, mode, word);
|
bus_write(addr, size, mode, word);
|
||||||
processor.nonsequential = true;
|
processor.nonsequential = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,7 @@ struct ARM {
|
||||||
virtual auto step(unsigned clocks) -> void = 0;
|
virtual auto step(unsigned clocks) -> void = 0;
|
||||||
virtual auto bus_idle(uint32 addr) -> void = 0;
|
virtual auto bus_idle(uint32 addr) -> void = 0;
|
||||||
virtual auto bus_read(uint32 addr, uint32 size, bool mode) -> uint32 = 0;
|
virtual auto bus_read(uint32 addr, uint32 size, bool mode) -> uint32 = 0;
|
||||||
virtual auto bus_load(uint32 addr, uint32 size, bool mode) -> uint32 = 0;
|
|
||||||
virtual auto bus_write(uint32 addr, uint32 size, bool mode, uint32 word) -> void = 0;
|
virtual auto bus_write(uint32 addr, uint32 size, bool mode, uint32 word) -> void = 0;
|
||||||
virtual auto bus_store(uint32 addr, uint32 size, bool mode, uint32 word) -> void = 0;
|
|
||||||
|
|
||||||
//arm.cpp
|
//arm.cpp
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
|
@ -1,27 +1,16 @@
|
||||||
#include <processor/processor.hpp>
|
#include <processor/processor.hpp>
|
||||||
#include "gsu.hpp"
|
#include "gsu.hpp"
|
||||||
|
|
||||||
|
//note: multiplication results *may* sometimes be invalid when both CLSR and MS0 are set
|
||||||
|
//the product of multiplication in this mode (21mhz + fast-multiply) has not been analyzed;
|
||||||
|
//however, the timing of this mode has been confirmed to work as specified below
|
||||||
|
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
#include "instructions.cpp"
|
#include "instructions.cpp"
|
||||||
#include "table.cpp"
|
#include "table.cpp"
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
|
|
||||||
//note: multiplication results *may* sometimes be invalid when both CLSR and MS0 are set
|
|
||||||
//the product of multiplication in this mode (21mhz + fast-multiply) has not been analyzed;
|
|
||||||
//however, the timing of this mode has been confirmed to work as specified below
|
|
||||||
auto GSU::cache_access_speed() -> unsigned {
|
|
||||||
if(clockmode == 1) return 2;
|
|
||||||
if(clockmode == 2) return 1;
|
|
||||||
return regs.clsr ? 1 : 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto GSU::memory_access_speed() -> unsigned {
|
|
||||||
if(clockmode == 1) return 6;
|
|
||||||
if(clockmode == 2) return 5;
|
|
||||||
return regs.clsr ? 5 : 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto GSU::power() -> void {
|
auto GSU::power() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
struct GSU {
|
struct GSU {
|
||||||
unsigned clockmode; //0 = selectable; 1 = force 10.74mhz; 2 = force 21.48mhz
|
|
||||||
#include "registers.hpp"
|
#include "registers.hpp"
|
||||||
|
|
||||||
virtual auto step(unsigned clocks) -> void = 0;
|
virtual auto step(unsigned clocks) -> void = 0;
|
||||||
|
@ -23,9 +22,6 @@ struct GSU {
|
||||||
virtual auto cache_flush() -> void = 0;
|
virtual auto cache_flush() -> void = 0;
|
||||||
|
|
||||||
//gsu.cpp
|
//gsu.cpp
|
||||||
auto cache_access_speed() -> unsigned;
|
|
||||||
auto memory_access_speed() -> unsigned;
|
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
|
|
|
@ -383,7 +383,7 @@ auto GSU::op_mult_r() {
|
||||||
regs.sfr.s = (regs.dr() & 0x8000);
|
regs.sfr.s = (regs.dr() & 0x8000);
|
||||||
regs.sfr.z = (regs.dr() == 0);
|
regs.sfr.z = (regs.dr() == 0);
|
||||||
regs.reset();
|
regs.reset();
|
||||||
if(!regs.cfgr.ms0) step(cache_access_speed());
|
if(!regs.cfgr.ms0) step(regs.clsr ? 1 : 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
//$80-8f(alt1): umult rN
|
//$80-8f(alt1): umult rN
|
||||||
|
@ -393,7 +393,7 @@ auto GSU::op_umult_r() {
|
||||||
regs.sfr.s = (regs.dr() & 0x8000);
|
regs.sfr.s = (regs.dr() & 0x8000);
|
||||||
regs.sfr.z = (regs.dr() == 0);
|
regs.sfr.z = (regs.dr() == 0);
|
||||||
regs.reset();
|
regs.reset();
|
||||||
if(!regs.cfgr.ms0) step(cache_access_speed());
|
if(!regs.cfgr.ms0) step(regs.clsr ? 1 : 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
//$80-8f(alt2): mult #N
|
//$80-8f(alt2): mult #N
|
||||||
|
@ -403,7 +403,7 @@ auto GSU::op_mult_i() {
|
||||||
regs.sfr.s = (regs.dr() & 0x8000);
|
regs.sfr.s = (regs.dr() & 0x8000);
|
||||||
regs.sfr.z = (regs.dr() == 0);
|
regs.sfr.z = (regs.dr() == 0);
|
||||||
regs.reset();
|
regs.reset();
|
||||||
if(!regs.cfgr.ms0) step(cache_access_speed());
|
if(!regs.cfgr.ms0) step(regs.clsr ? 1 : 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
//$80-8f(alt3): umult #N
|
//$80-8f(alt3): umult #N
|
||||||
|
@ -413,7 +413,7 @@ auto GSU::op_umult_i() {
|
||||||
regs.sfr.s = (regs.dr() & 0x8000);
|
regs.sfr.s = (regs.dr() & 0x8000);
|
||||||
regs.sfr.z = (regs.dr() == 0);
|
regs.sfr.z = (regs.dr() == 0);
|
||||||
regs.reset();
|
regs.reset();
|
||||||
if(!regs.cfgr.ms0) step(cache_access_speed());
|
if(!regs.cfgr.ms0) step(regs.clsr ? 1 : 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
//$90: sbk
|
//$90: sbk
|
||||||
|
@ -499,7 +499,7 @@ auto GSU::op_fmult() {
|
||||||
regs.sfr.cy = (result & 0x8000);
|
regs.sfr.cy = (result & 0x8000);
|
||||||
regs.sfr.z = (regs.dr() == 0);
|
regs.sfr.z = (regs.dr() == 0);
|
||||||
regs.reset();
|
regs.reset();
|
||||||
step(4 + (regs.cfgr.ms0 << 2));
|
step((regs.cfgr.ms0 ? 3 : 7) * (regs.clsr ? 1 : 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
//$9f(alt1): lmult
|
//$9f(alt1): lmult
|
||||||
|
@ -511,7 +511,7 @@ auto GSU::op_lmult() {
|
||||||
regs.sfr.cy = (result & 0x8000);
|
regs.sfr.cy = (result & 0x8000);
|
||||||
regs.sfr.z = (regs.dr() == 0);
|
regs.sfr.z = (regs.dr() == 0);
|
||||||
regs.reset();
|
regs.reset();
|
||||||
step(4 + (regs.cfgr.ms0 << 2));
|
step((regs.cfgr.ms0 ? 3 : 7) * (regs.clsr ? 1 : 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
//$a0-af(alt0): ibt rN,#pp
|
//$a0-af(alt0): ibt rN,#pp
|
||||||
|
@ -618,7 +618,7 @@ auto GSU::op_getc() {
|
||||||
//$df(alt2): ramb
|
//$df(alt2): ramb
|
||||||
auto GSU::op_ramb() {
|
auto GSU::op_ramb() {
|
||||||
rambuffer_sync();
|
rambuffer_sync();
|
||||||
regs.rambr = regs.sr();
|
regs.rambr = regs.sr() & 0x01;
|
||||||
regs.reset();
|
regs.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ struct reg16_t {
|
||||||
|
|
||||||
inline auto operator = (const reg16_t& i) { return assign(i); }
|
inline auto operator = (const reg16_t& i) { return assign(i); }
|
||||||
|
|
||||||
|
reg16_t() = default;
|
||||||
reg16_t(const reg16_t&) = delete;
|
reg16_t(const reg16_t&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
auto GSU::serialize(serializer& s) -> void {
|
auto GSU::serialize(serializer& s) -> void {
|
||||||
s.integer(clockmode);
|
|
||||||
|
|
||||||
s.integer(regs.pipeline);
|
s.integer(regs.pipeline);
|
||||||
s.integer(regs.ramaddr);
|
s.integer(regs.ramaddr);
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,10 @@ struct ArmDSP : Processor::ARM, Coprocessor {
|
||||||
static void Enter();
|
static void Enter();
|
||||||
void enter();
|
void enter();
|
||||||
|
|
||||||
void step(unsigned clocks);
|
void step(unsigned clocks) override;
|
||||||
void bus_idle(uint32 addr);
|
void bus_idle(uint32 addr) override;
|
||||||
uint32 bus_read(uint32 addr, uint32 size, bool mode);
|
uint32 bus_read(uint32 addr, uint32 size, bool mode) override;
|
||||||
uint32 bus_load(uint32 addr, uint32 size, bool mode);
|
void bus_write(uint32 addr, uint32 size, bool mode, uint32 word) override;
|
||||||
void bus_write(uint32 addr, uint32 size, bool mode, uint32 word);
|
|
||||||
void bus_store(uint32 addr, uint32 size, bool mode, uint32 word);
|
|
||||||
|
|
||||||
uint8 mmio_read(unsigned addr);
|
uint8 mmio_read(unsigned addr);
|
||||||
void mmio_write(unsigned addr, uint8 data);
|
void mmio_write(unsigned addr, uint8 data);
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#ifdef ARMDSP_CPP
|
#ifdef ARMDSP_CPP
|
||||||
|
|
||||||
|
//note: timings are completely unverified
|
||||||
|
//due to the ST018 chip design (on-die ROM), testing is nearly impossible
|
||||||
|
|
||||||
void ArmDSP::bus_idle(uint32 addr) {
|
void ArmDSP::bus_idle(uint32 addr) {
|
||||||
step(1);
|
step(1);
|
||||||
}
|
}
|
||||||
|
@ -44,10 +47,6 @@ uint32 ArmDSP::bus_read(uint32 addr, uint32 size, bool mode) {
|
||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 ArmDSP::bus_load(uint32 addr, uint32 size, bool mode) {
|
|
||||||
return bus_read(addr, size, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArmDSP::bus_write(uint32 addr, uint32 size, bool mode, uint32 word) {
|
void ArmDSP::bus_write(uint32 addr, uint32 size, bool mode, uint32 word) {
|
||||||
step(1);
|
step(1);
|
||||||
|
|
||||||
|
@ -102,8 +101,4 @@ void ArmDSP::bus_write(uint32 addr, uint32 size, bool mode, uint32 word) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArmDSP::bus_store(uint32 addr, uint32 size, bool mode, uint32 word) {
|
|
||||||
return bus_write(addr, size, mode, word);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -60,7 +60,7 @@ void Event::submitScore() {
|
||||||
data.append("ba:", ba[0], ",", ba[1], "\n");
|
data.append("ba:", ba[0], ",", ba[1], "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
lstring side = interface->server().split<1>("@");
|
/*lstring side = interface->server().split<1>("@");
|
||||||
string username = side(0).split<1>(":")(0);
|
string username = side(0).split<1>(":")(0);
|
||||||
string password = side(0).split<1>(":")(1);
|
string password = side(0).split<1>(":")(1);
|
||||||
side(1).ltrim("http://");
|
side(1).ltrim("http://");
|
||||||
|
@ -71,7 +71,7 @@ void Event::submitScore() {
|
||||||
string hostport = side(1);
|
string hostport = side(1);
|
||||||
if(hostport.empty()) hostport = "80";
|
if(hostport.empty()) hostport = "80";
|
||||||
|
|
||||||
/*http server;
|
http server;
|
||||||
if(server.connect(hostname, decimal(hostport))) {
|
if(server.connect(hostname, decimal(hostport))) {
|
||||||
string content = {
|
string content = {
|
||||||
"username:", username, "\n",
|
"username:", username, "\n",
|
||||||
|
|
|
@ -66,7 +66,7 @@ auto SuperFX::rpix(uint8 x, uint8 y) -> uint8 {
|
||||||
|
|
||||||
for(unsigned n = 0; n < bpp; n++) {
|
for(unsigned n = 0; n < bpp; n++) {
|
||||||
unsigned byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 };
|
unsigned byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 };
|
||||||
step(memory_access_speed());
|
step(regs.clsr ? 5 : 6);
|
||||||
data |= ((bus_read(addr + byte) >> x) & 1) << n;
|
data |= ((bus_read(addr + byte) >> x) & 1) << n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,11 +94,11 @@ auto SuperFX::pixelcache_flush(pixelcache_t& cache) -> void {
|
||||||
uint8 data = 0x00;
|
uint8 data = 0x00;
|
||||||
for(unsigned x = 0; x < 8; x++) data |= ((cache.data[x] >> n) & 1) << x;
|
for(unsigned x = 0; x < 8; x++) data |= ((cache.data[x] >> n) & 1) << x;
|
||||||
if(cache.bitpend != 0xff) {
|
if(cache.bitpend != 0xff) {
|
||||||
step(memory_access_speed());
|
step(regs.clsr ? 5 : 6);
|
||||||
data &= cache.bitpend;
|
data &= cache.bitpend;
|
||||||
data |= bus_read(addr + byte) & ~cache.bitpend;
|
data |= bus_read(addr + byte) & ~cache.bitpend;
|
||||||
}
|
}
|
||||||
step(memory_access_speed());
|
step(regs.clsr ? 5 : 6);
|
||||||
bus_write(addr + byte, data);
|
bus_write(addr + byte, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,12 +43,12 @@ auto SuperFX::op_read(uint16 addr) -> uint8 {
|
||||||
unsigned dp = offset & 0xfff0;
|
unsigned dp = offset & 0xfff0;
|
||||||
unsigned sp = (regs.pbr << 16) + ((regs.cbr + dp) & 0xfff0);
|
unsigned sp = (regs.pbr << 16) + ((regs.cbr + dp) & 0xfff0);
|
||||||
for(unsigned n = 0; n < 16; n++) {
|
for(unsigned n = 0; n < 16; n++) {
|
||||||
step(memory_access_speed());
|
step(regs.clsr ? 5 : 6);
|
||||||
cache.buffer[dp++] = bus_read(sp++);
|
cache.buffer[dp++] = bus_read(sp++);
|
||||||
}
|
}
|
||||||
cache.valid[offset >> 4] = true;
|
cache.valid[offset >> 4] = true;
|
||||||
} else {
|
} else {
|
||||||
step(cache_access_speed());
|
step(regs.clsr ? 1 : 2);
|
||||||
}
|
}
|
||||||
return cache.buffer[offset];
|
return cache.buffer[offset];
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,12 @@ auto SuperFX::op_read(uint16 addr) -> uint8 {
|
||||||
if(regs.pbr <= 0x5f) {
|
if(regs.pbr <= 0x5f) {
|
||||||
//$[00-5f]:[0000-ffff] ROM
|
//$[00-5f]:[0000-ffff] ROM
|
||||||
rombuffer_sync();
|
rombuffer_sync();
|
||||||
step(memory_access_speed());
|
step(regs.clsr ? 5 : 6);
|
||||||
return bus_read((regs.pbr << 16) + addr);
|
return bus_read((regs.pbr << 16) + addr);
|
||||||
} else {
|
} else {
|
||||||
//$[60-7f]:[0000-ffff] RAM
|
//$[60-7f]:[0000-ffff] RAM
|
||||||
rambuffer_sync();
|
rambuffer_sync();
|
||||||
step(memory_access_speed());
|
step(regs.clsr ? 5 : 6);
|
||||||
return bus_read((regs.pbr << 16) + addr);
|
return bus_read((regs.pbr << 16) + addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ auto SuperFX::mmio_write(unsigned addr, uint8 data) -> void {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x3033: {
|
case 0x3033: {
|
||||||
regs.bramr = data;
|
regs.bramr = data & 0x01;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x3034: {
|
case 0x3034: {
|
||||||
|
@ -104,7 +104,7 @@ auto SuperFX::mmio_write(unsigned addr, uint8 data) -> void {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x3039: {
|
case 0x3039: {
|
||||||
regs.clsr = data;
|
regs.clsr = data & 0x01;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 0x303a: {
|
case 0x303a: {
|
||||||
|
|
|
@ -5,7 +5,6 @@ auto SuperFX::serialize(serializer& s) -> void {
|
||||||
Thread::serialize(s);
|
Thread::serialize(s);
|
||||||
|
|
||||||
s.array(ram.data(), ram.size());
|
s.array(ram.data(), ram.size());
|
||||||
s.integer(instruction_counter);
|
|
||||||
s.integer(r15_modified);
|
s.integer(r15_modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,17 +25,12 @@ auto SuperFX::enter() -> void {
|
||||||
|
|
||||||
if(regs.sfr.g == 0) {
|
if(regs.sfr.g == 0) {
|
||||||
step(6);
|
step(6);
|
||||||
synchronize_cpu();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
(this->*opcode_table[(regs.sfr & 0x0300) + peekpipe()])();
|
unsigned opcode = (regs.sfr & 0x0300) + peekpipe();
|
||||||
|
(this->*opcode_table[opcode])();
|
||||||
if(r15_modified == false) regs.r[15]++;
|
if(r15_modified == false) regs.r[15]++;
|
||||||
|
|
||||||
if(++instruction_counter >= 128) {
|
|
||||||
instruction_counter = 0;
|
|
||||||
synchronize_cpu();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +55,6 @@ auto SuperFX::power() -> void {
|
||||||
auto SuperFX::reset() -> void {
|
auto SuperFX::reset() -> void {
|
||||||
GSU::reset();
|
GSU::reset();
|
||||||
create(SuperFX::Enter, system.cpu_frequency());
|
create(SuperFX::Enter, system.cpu_frequency());
|
||||||
instruction_counter = 0;
|
|
||||||
memory_reset();
|
memory_reset();
|
||||||
timing_reset();
|
timing_reset();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,6 @@ struct SuperFX : Processor::GSU, Coprocessor {
|
||||||
|
|
||||||
//serialization.cpp
|
//serialization.cpp
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
privileged:
|
|
||||||
unsigned instruction_counter = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SuperFX superfx;
|
extern SuperFX superfx;
|
||||||
|
|
|
@ -26,7 +26,7 @@ auto SuperFX::rombuffer_sync() -> void {
|
||||||
|
|
||||||
auto SuperFX::rombuffer_update() -> void {
|
auto SuperFX::rombuffer_update() -> void {
|
||||||
regs.sfr.r = 1;
|
regs.sfr.r = 1;
|
||||||
regs.romcl = memory_access_speed();
|
regs.romcl = regs.clsr ? 5 : 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SuperFX::rombuffer_read() -> uint8 {
|
auto SuperFX::rombuffer_read() -> uint8 {
|
||||||
|
@ -45,7 +45,7 @@ auto SuperFX::rambuffer_read(uint16 addr) -> uint8 {
|
||||||
|
|
||||||
auto SuperFX::rambuffer_write(uint16 addr, uint8 data) -> void {
|
auto SuperFX::rambuffer_write(uint16 addr, uint8 data) -> void {
|
||||||
rambuffer_sync();
|
rambuffer_sync();
|
||||||
regs.ramcl = memory_access_speed();
|
regs.ramcl = regs.clsr ? 5 : 6;
|
||||||
regs.ramar = addr;
|
regs.ramar = addr;
|
||||||
regs.ramdr = data;
|
regs.ramdr = data;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue