From 533aa97011870e5d512ec12404d51aab14f95d19 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 8 Mar 2012 00:03:15 +1100 Subject: [PATCH] Update to v086r16 release. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit byuu says: Cydrak, I moved the step from the opcode decoder and opcodes themselves into bus_(read,write)(byte,word), to minimize code. If that's not feasible for some reason, please let me know and I'll change it back to your latest WIP. This has your carry flag fix, the timer skeleton (doesn't really work yet), the Booth two-bit steps, and the carry flag clear thing inside multiply ops. Also added the aforementioned reset delay and reset bit stuff, and fixed the steps to 21MHz for instructions and 64KHz for reset pulse. I wasn't sure about the shifter extra cycles. I only saw it inside one of the four (or was it three?) opcodes that have shifter functions. Shouldn't it be in all of them? The game does indeed appear to be fully playable now, but the AI doesn't exactly match my real cartridge. This could be for any number of reasons: ARM CPU bug, timer behavior bug, oscillator differences between my real hardware and the emulator, etc. However ... the AI is 100% predictable every time, both under emulation and on real hardware. - For the first step, move 九-1 to 八-1. - The opponent moves 三-3 to 四-3. - Now move 七-1 to 六-1. - The opponent moves 二-2 to 八-8. However, on my real SNES, the opponent moves 一-3 to 二-4. --- bsnes/base/base.hpp | 2 +- bsnes/nall/bit.hpp | 18 +++++--- bsnes/nall/stack.hpp | 26 ----------- bsnes/nall/string/utility.hpp | 3 +- bsnes/nall/vector.hpp | 21 ++++++++- bsnes/snes/chip/armdsp/armdsp.cpp | 65 ++++++++++++---------------- bsnes/snes/chip/armdsp/armdsp.hpp | 1 + bsnes/snes/chip/armdsp/memory.cpp | 13 ++++++ bsnes/snes/chip/armdsp/opcodes.cpp | 19 ++++++-- bsnes/snes/chip/armdsp/registers.hpp | 5 ++- 10 files changed, 97 insertions(+), 76 deletions(-) delete mode 100755 bsnes/nall/stack.hpp 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;