diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index 8a8283fe..fddac720 100755 --- a/bsnes/base/base.hpp +++ b/bsnes/base/base.hpp @@ -1,7 +1,7 @@ #ifndef BASE_HPP #define BASE_HPP -const char Version[] = "086.15"; +const char Version[] = "086.16"; #include #include diff --git a/bsnes/nall/bit.hpp b/bsnes/nall/bit.hpp index 2732efce..78b75493 100755 --- a/bsnes/nall/bit.hpp +++ b/bsnes/nall/bit.hpp @@ -5,26 +5,34 @@ namespace nall { template - constexpr inline type_t uclamp(const type_t x) { + constexpr inline + typename type_if::type + uclamp(const type_t x) { enum : type_t { b = 1ull << (bits - 1), y = b * 2 - 1 }; return y + ((x - y) & -(x < y)); //min(x, y); } template - constexpr inline type_t uclip(const type_t x) { + constexpr inline + typename type_if::type + uclip(const type_t x) { enum : type_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; return (x & m); } template - constexpr inline type_t sclamp(const type_t x) { + constexpr inline + typename type_if::type + sclamp(const type_t x) { enum : type_t { b = 1ull << (bits - 1), m = b - 1 }; return (x > m) ? m : (x < -b) ? -b : x; } template - constexpr inline type_t sclip(const type_t x) { - typedef typename type_if::value, unsigned, uintmax_t>::type cast_t; + constexpr inline + typename type_if::type + sclip(const type_t x) { + typedef typename type_if::type cast_t; enum : cast_t { b = 1ull << (bits - 1), m = b * 2 - 1 }; return ((x & m) ^ b) - b; } diff --git a/bsnes/nall/stack.hpp b/bsnes/nall/stack.hpp deleted file mode 100755 index fe8e16a1..00000000 --- a/bsnes/nall/stack.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef NALL_STACK_HPP -#define NALL_STACK_HPP - -#include - -namespace nall { - template struct stack : public linear_vector { - void push(const T &value) { - linear_vector::append(value); - } - - T pull() { - if(linear_vector::size() == 0) throw; - T value = linear_vector::operator[](linear_vector::size() - 1); - linear_vector::remove(linear_vector::size() - 1); - return value; - } - - T& operator()() { - if(linear_vector::size() == 0) throw; - return linear_vector::operator[](linear_vector::size() - 1); - } - }; -} - -#endif diff --git a/bsnes/nall/string/utility.hpp b/bsnes/nall/string/utility.hpp index 355451c9..b2f93d2c 100755 --- a/bsnes/nall/string/utility.hpp +++ b/bsnes/nall/string/utility.hpp @@ -36,12 +36,13 @@ bool quotecopy(char *&t, T *&p) { string substr(const char *src, unsigned start, unsigned length) { string dest; - dest.reserve(length + 1); if(length == ~0u) { //copy entire string + dest.reserve(strlen(src + start) + 1); strcpy(dest(), src + start); } else { //copy partial string + dest.reserve(length + 1); strmcpy(dest(), src + start, length + 1); } return dest; diff --git a/bsnes/nall/vector.hpp b/bsnes/nall/vector.hpp index 9d4a76b4..efa522a8 100755 --- a/bsnes/nall/vector.hpp +++ b/bsnes/nall/vector.hpp @@ -66,11 +66,20 @@ namespace nall { insert(0, data); } - void remove(unsigned index, unsigned count = 1) { + void remove(unsigned index = ~0u, unsigned count = 1) { + if(index == ~0) index = objectsize ? objectsize - 1 : 0; for(unsigned n = index; count + n < objectsize; n++) pool[n] = pool[count + n]; objectsize = (count + index >= objectsize) ? index : objectsize - count; } + T take(unsigned index = ~0u) { + if(index == ~0) index = objectsize ? objectsize - 1 : 0; + if(index >= objectsize) throw exception_out_of_bounds(); + T item = pool[index]; + remove(index); + return item; + } + void sort() { nall::sort(pool, objectsize); } @@ -84,6 +93,16 @@ namespace nall { return { false, 0u }; } + T& first() { + if(objectsize == 0) throw exception_out_of_bounds(); + return pool[0]; + } + + T& last() { + if(objectsize == 0) throw exception_out_of_bounds(); + return pool[objectsize - 1]; + } + //access inline T& operator[](unsigned position) { if(position >= objectsize) throw exception_out_of_bounds(); diff --git a/bsnes/snes/chip/armdsp/armdsp.cpp b/bsnes/snes/chip/armdsp/armdsp.cpp index 474cb11e..ca58d0f2 100755 --- a/bsnes/snes/chip/armdsp/armdsp.cpp +++ b/bsnes/snes/chip/armdsp/armdsp.cpp @@ -16,15 +16,13 @@ void ArmDSP::Enter() { armdsp.enter(); } void ArmDSP::enter() { //reset hold delay while(bridge.reset) { - step(4); - synchronize_cpu(); + tick(); continue; } //reset sequence delay if(bridge.ready == false) { - step(4096); //todo: verify cycle count - synchronize_cpu(); + tick(65536); bridge.ready = true; } @@ -33,17 +31,11 @@ void ArmDSP::enter() { scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); } - step(4); //todo: how many cycles per instruction? - synchronize_cpu(); - if(exception) { print("* ARM unknown instruction\n"); print("\n", disassemble_registers()); print("\n", disassemble_opcode(pipeline.instruction.address), "\n"); - while(true) { - step(21477272); - synchronize_cpu(); - } + while(true) tick(frequency); } if(pipeline.reload) { @@ -58,16 +50,17 @@ void ArmDSP::enter() { pipeline.prefetch.opcode = bus_readword(r[15]); r[15].step(); - pipeline.mdr.address = r[15]; - pipeline.mdr.opcode = bus_readword(r[15]); + //todo: bus_readword() calls tick(); so we need to prefetch this as well + //pipeline.mdr.address = r[15]; + //pipeline.mdr.opcode = bus_readword(r[15]); - if(pipeline.instruction.address == 0x00000208) trace = 1; + //if(pipeline.instruction.address == 0x00000208) trace = 1; if(trace) { print("\n", disassemble_registers(), "\n"); print(disassemble_opcode(pipeline.instruction.address), "\n"); usleep(200000); } - trace = 0; + //trace = 0; instruction = pipeline.instruction.opcode; if(!condition()) continue; @@ -86,6 +79,13 @@ void ArmDSP::enter() { } } +void ArmDSP::tick(unsigned clocks) { + if(bridge.timer && --bridge.timer == 0) bridge.busy = false; + + step(clocks); + synchronize_cpu(); +} + //MMIO: $00-3f|80-bf:3800-38ff //3800-3807 mirrored throughout //a0 ignored @@ -100,42 +100,33 @@ uint8 ArmDSP::mmio_read(unsigned addr) { if(bridge.armtocpu.ready) { bridge.armtocpu.ready = false; data = bridge.armtocpu.data; - print("* r3800 = ", hex<2>(data), "\n"); } } if(addr == 0x3802) { + bridge.timer = 0; + bridge.busy = false; } if(addr == 0x3804) { data = bridge.status(); } - if(0) { - print("* r", hex<6>(addr), " = ", hex<2>(data), "\n"); - usleep(200000); - } - return data; } void ArmDSP::mmio_write(unsigned addr, uint8 data) { cpu.synchronize_coprocessors(); - if(0) { - print("* w", hex<6>(addr), " = ", hex<2>(data), "\n"); - usleep(200000); - } - addr &= 0xff06; if(addr == 0x3802) { bridge.cputoarm.ready = true; bridge.cputoarm.data = data; - print("* w3802 = ", hex<2>(data), "\n"); } if(addr == 0x3804) { + data &= 1; if(!bridge.reset && data) arm_reset(); bridge.reset = data; } @@ -151,14 +142,6 @@ void ArmDSP::unload() { } void ArmDSP::power() { - string filename = { dir(interface->path(Cartridge::Slot::Base, "st018.rom")), "disassembly.txt" }; - file fp; - fp.open(filename, file::mode::write); - for(unsigned n = 0; n < 128 * 1024; n += 4) { - fp.print(disassemble_opcode(n), "\n"); - } - fp.close(); - for(unsigned n = 0; n < 16 * 1024; n++) programRAM[n] = random(0x00); } @@ -168,9 +151,15 @@ void ArmDSP::reset() { } void ArmDSP::arm_reset() { - bridge.ready = false; create(ArmDSP::Enter, 21477272); + bridge.ready = false; + bridge.timer = 0; + bridge.timerlatch = 0; + bridge.busy = false; + bridge.cputoarm.ready = false; + bridge.armtocpu.ready = false; + for(auto &rd : r) rd = 0; shiftercarry = 0; exception = 0; @@ -179,8 +168,8 @@ void ArmDSP::arm_reset() { } ArmDSP::ArmDSP() { - firmware = new uint8[160 * 1024]; - programRAM = new uint8[16 * 1024]; + firmware = new uint8[160 * 1024](); + programRAM = new uint8[16 * 1024](); programROM = &firmware[0]; dataROM = &firmware[128 * 1024]; diff --git a/bsnes/snes/chip/armdsp/armdsp.hpp b/bsnes/snes/chip/armdsp/armdsp.hpp index 6f339609..bae7553a 100755 --- a/bsnes/snes/chip/armdsp/armdsp.hpp +++ b/bsnes/snes/chip/armdsp/armdsp.hpp @@ -10,6 +10,7 @@ struct ArmDSP : public Coprocessor { static void Enter(); void enter(); + void tick(unsigned clocks = 1); void init(); void load(); diff --git a/bsnes/snes/chip/armdsp/memory.cpp b/bsnes/snes/chip/armdsp/memory.cpp index 0083146c..cf2a0fca 100755 --- a/bsnes/snes/chip/armdsp/memory.cpp +++ b/bsnes/snes/chip/armdsp/memory.cpp @@ -42,17 +42,29 @@ void ArmDSP::bus_write(uint32 addr, uint8 data) { bridge.armtocpu.data = data; return; } + + if(addr == 0x40000020) bridge.timerlatch = (bridge.timerlatch & 0xffff00) | (data << 0); + if(addr == 0x40000024) bridge.timerlatch = (bridge.timerlatch & 0xff00ff) | (data << 8); + if(addr == 0x40000028) bridge.timerlatch = (bridge.timerlatch & 0x00ffff) | (data << 16); + + if(addr == 0x40000028) { + bridge.timer = bridge.timerlatch; + bridge.busy = !bridge.timer; + } } uint32 ArmDSP::bus_readbyte(uint32 addr) { + tick(); return bus_read(addr); } void ArmDSP::bus_writebyte(uint32 addr, uint32 data) { + tick(); return bus_write(addr, data); } uint32 ArmDSP::bus_readword(uint32 addr) { + tick(); addr &= ~3; return ( (bus_read(addr + 0) << 0) @@ -63,6 +75,7 @@ uint32 ArmDSP::bus_readword(uint32 addr) { } void ArmDSP::bus_writeword(uint32 addr, uint32 data) { + tick(); addr &= ~3; bus_write(addr + 0, data >> 0); bus_write(addr + 1, data >> 8); diff --git a/bsnes/snes/chip/armdsp/opcodes.cpp b/bsnes/snes/chip/armdsp/opcodes.cpp index b6425fa4..007a8842 100755 --- a/bsnes/snes/chip/armdsp/opcodes.cpp +++ b/bsnes/snes/chip/armdsp/opcodes.cpp @@ -51,10 +51,11 @@ void ArmDSP::opcode(uint32 rm) { auto math = [&](uint32 source, uint32 modify, bool carry) { uint32 result = source + modify + carry; if(save) { + uint32 overflow = ~(source ^ modify) & (source ^ result); cpsr.n = result >> 31; cpsr.z = result == 0; - cpsr.c = result < source; - cpsr.v = ~(source ^ modify) & (source ^ result) & (1u << 31); + cpsr.c = (1u << 31) & (overflow ^ source ^ modify ^ result); + cpsr.v = (1u << 31) & (overflow); } return result; }; @@ -135,11 +136,23 @@ void ArmDSP::op_multiply() { uint4 s = instruction >> 8; uint4 m = instruction >> 0; + //Booth's algorithm: two bit steps + uint32 temp = r[s]; + while(temp) { + temp >>= 2; + tick(); + } r[d] = r[m] * r[s]; - if(accumulate) r[d] += r[n]; + + if(accumulate) { + tick(); + r[d] += r[n]; + } + if(save) { cpsr.n = r[d] >> 31; cpsr.z = r[d] == 0; + cpsr.c = 0; //undefined } } diff --git a/bsnes/snes/chip/armdsp/registers.hpp b/bsnes/snes/chip/armdsp/registers.hpp index fce1ee37..8cbaec10 100755 --- a/bsnes/snes/chip/armdsp/registers.hpp +++ b/bsnes/snes/chip/armdsp/registers.hpp @@ -14,11 +14,14 @@ struct Bridge { }; Buffer cputoarm; Buffer armtocpu; + uint32 timer; + uint32 timerlatch; bool reset; bool ready; + bool busy; uint8 status() const { - return (ready << 7) | (cputoarm.ready << 3) | (armtocpu.ready << 0) | 4; + return (ready << 7) | (cputoarm.ready << 3) | (busy << 2) | (armtocpu.ready << 0); } } bridge;