From 3bd29088d199cfc9fba8adcd1fd1f7c759f4186b Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Fri, 17 Dec 2010 21:54:28 +1100 Subject: [PATCH] Update to v072r09 release. Unfortunately, I missed the v072r08 release; it was taken down before I saw the announcement. byuu says (about v072r08): This WIP adds NEC uPD77C25 emulation. Unfortunately it's not at all functional yet, there are way too many things I don't understand about the chip. I'm absolutely going to need help to complete this. [...] For now, you need the included PCB XML to manually map the program/data ROM in, which are included with the archive. You'll have to rewrite the map yourself to run other DSP-1 games, unless they have the same layout as Mario Kart. I am using the US [!] version, name it mariokart.sfc and put all the archive files and the ROM together. From here, bsnes will load up the ROMs, and start executing instructions. Since the emulation is so incomplete, it just deadlocks on the "Nintendo" logo as if there were no DSP on the cart at all, but if you enable tracing, you'll see it actually starts doing a lot of stuff before getting stuck in a really long and confusing loop. [Note: the DSP-1B program and data ROMs are not included in this commit. The PCB XML file mentioned above looks like this: Save it as 'mariokart.xml'] byuu says (about v072r09): Fixes OP/LD RQM=1 on DR modify, Mario Kart can get in-game, but the track is completely corrupted. Reorders order of operations for OP, in an attempt to mimic parallelism. Added support for OP KLM DST. Added S1 flag setting, probably not correct. --- bsnes/Makefile | 2 +- bsnes/snes/Makefile | 3 +- bsnes/snes/cartridge/cartridge.cpp | 1 + bsnes/snes/cartridge/cartridge.hpp | 2 + bsnes/snes/cartridge/xml.cpp | 37 ++ bsnes/snes/chip/chip.hpp | 1 + bsnes/snes/chip/upd77c25/disassembler.cpp | 205 +++++++++ bsnes/snes/chip/upd77c25/upd77c25.cpp | 507 ++++++++++++++++++++++ bsnes/snes/chip/upd77c25/upd77c25.hpp | 97 +++++ bsnes/snes/snes.hpp | 7 +- bsnes/snes/system/system.cpp | 5 + 11 files changed, 864 insertions(+), 3 deletions(-) create mode 100755 bsnes/snes/chip/upd77c25/disassembler.cpp create mode 100755 bsnes/snes/chip/upd77c25/upd77c25.cpp create mode 100755 bsnes/snes/chip/upd77c25/upd77c25.hpp diff --git a/bsnes/Makefile b/bsnes/Makefile index 1e08781e..06a58342 100755 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -1,6 +1,6 @@ include nall/Makefile snes := snes -profile := performance +profile := compatibility ui := ui-phoenix # compiler diff --git a/bsnes/snes/Makefile b/bsnes/snes/Makefile index e47c23ae..ed3a9b99 100755 --- a/bsnes/snes/Makefile +++ b/bsnes/snes/Makefile @@ -3,7 +3,7 @@ snes_objects += snes-system snes_objects += snes-cartridge snes-cheat snes_objects += snes-memory snes-cpucore snes-smpcore snes_objects += snes-cpu snes-smp snes-dsp snes-ppu -snes_objects += snes-supergameboy snes-superfx snes-sa1 +snes_objects += snes-supergameboy snes-superfx snes-sa1 snes-upd77c25 snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110 snes_objects += snes-cx4 snes-dsp1 snes-dsp2 snes-dsp3 snes-dsp4 snes_objects += snes-obc1 snes-st0010 snes-st0011 snes-st0018 @@ -47,6 +47,7 @@ obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(call rwildcard,$(snes)/cheat/) obj/snes-supergameboy.o: $(snes)/chip/supergameboy/supergameboy.cpp $(call rwildcard,$(snes)/chip/supergameboy/) obj/snes-superfx.o : $(snes)/chip/superfx/superfx.cpp $(call rwildcard,$(snes)/chip/superfx/) obj/snes-sa1.o : $(snes)/chip/sa1/sa1.cpp $(call rwildcard,$(snes)/chip/sa1/) +obj/snes-upd77c25.o : $(snes)/chip/upd77c25/upd77c25.cpp $(call rwildcard,$(snes)/chip/upd77c25/) obj/snes-bsx.o : $(snes)/chip/bsx/bsx.cpp $(snes)/chip/bsx/* obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/* obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/* diff --git a/bsnes/snes/cartridge/cartridge.cpp b/bsnes/snes/cartridge/cartridge.cpp index c41931f1..3e177129 100755 --- a/bsnes/snes/cartridge/cartridge.cpp +++ b/bsnes/snes/cartridge/cartridge.cpp @@ -31,6 +31,7 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) { has_bsx_slot = false; has_superfx = false; has_sa1 = false; + has_upd77c25 = false; has_srtc = false; has_sdd1 = false; has_spc7110 = false; diff --git a/bsnes/snes/cartridge/cartridge.hpp b/bsnes/snes/cartridge/cartridge.hpp index 9c9a2004..62c69fc3 100755 --- a/bsnes/snes/cartridge/cartridge.hpp +++ b/bsnes/snes/cartridge/cartridge.hpp @@ -37,6 +37,7 @@ public: readonly has_bsx_slot; readonly has_superfx; readonly has_sa1; + readonly has_upd77c25; readonly has_srtc; readonly has_sdd1; readonly has_spc7110; @@ -88,6 +89,7 @@ private: void xml_parse_ram(xml_element&); void xml_parse_superfx(xml_element&); void xml_parse_sa1(xml_element&); + void xml_parse_upd77c25(xml_element&); void xml_parse_bsx(xml_element&); void xml_parse_sufamiturbo(xml_element&); void xml_parse_supergameboy(xml_element&); diff --git a/bsnes/snes/cartridge/xml.cpp b/bsnes/snes/cartridge/xml.cpp index ae0056d7..471a66e5 100755 --- a/bsnes/snes/cartridge/xml.cpp +++ b/bsnes/snes/cartridge/xml.cpp @@ -34,6 +34,7 @@ void Cartridge::parse_xml_cartridge(const char *data) { if(node.name == "ram") xml_parse_ram(node); if(node.name == "superfx") xml_parse_superfx(node); if(node.name == "sa1") xml_parse_sa1(node); + if(node.name == "upd77c25") xml_parse_upd77c25(node); if(node.name == "bsx") xml_parse_bsx(node); if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node); if(node.name == "supergameboy") xml_parse_supergameboy(node); @@ -226,6 +227,42 @@ void Cartridge::xml_parse_sa1(xml_element &root) { } } +void Cartridge::xml_parse_upd77c25(xml_element &root) { + has_upd77c25 = true; + + foreach(attr, root.attribute) { + if(attr.name == "program") { + upd77c25.program = attr.content; + } else if(attr.name == "data") { + upd77c25.data = attr.content; + } + } + + foreach(node, root.element) { + if(node.name == "dr") { + foreach(leaf, node.element) { + if(leaf.name == "map") { + Mapping m(upd77c25dr); + foreach(attr, leaf.attribute) { + if(attr.name == "address") xml_parse_address(m, attr.content); + } + mapping.append(m); + } + } + } else if(node.name == "sr") { + foreach(leaf, node.element) { + if(leaf.name == "map") { + Mapping m(upd77c25sr); + foreach(attr, leaf.attribute) { + if(attr.name == "address") xml_parse_address(m, attr.content); + } + mapping.append(m); + } + } + } + } +} + void Cartridge::xml_parse_bsx(xml_element &root) { if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return; diff --git a/bsnes/snes/chip/chip.hpp b/bsnes/snes/chip/chip.hpp index 6893952f..221847d2 100755 --- a/bsnes/snes/chip/chip.hpp +++ b/bsnes/snes/chip/chip.hpp @@ -6,6 +6,7 @@ struct Coprocessor : Processor { #include #include #include +#include #include #include #include diff --git a/bsnes/snes/chip/upd77c25/disassembler.cpp b/bsnes/snes/chip/upd77c25/disassembler.cpp new file mode 100755 index 00000000..ad95ab9b --- /dev/null +++ b/bsnes/snes/chip/upd77c25/disassembler.cpp @@ -0,0 +1,205 @@ +string UPD77C25::disassemble(uint11 ip) { + string output = { strhex<3>(ip), " " }; + uint24 opcode = programROM[ip]; + uint2 type = opcode >> 22; + + if(type == 0 || type == 1) { //OP,RT + uint2 pselect = opcode >> 20; + uint4 alu = opcode >> 16; + uint1 asl = opcode >> 15; + uint2 dpl = opcode >> 13; + uint4 dphm = opcode >> 9; + uint1 rpdcr = opcode >> 8; + uint4 src = opcode >> 4; + uint4 dst = opcode >> 0; + + switch(alu) { + case 0: output << "nop "; break; + case 1: output << "or "; break; + case 2: output << "and "; break; + case 3: output << "xor "; break; + case 4: output << "sub "; break; + case 5: output << "add "; break; + case 6: output << "sbb "; break; + case 7: output << "adc "; break; + case 8: output << "dec "; break; + case 9: output << "inc "; break; + case 10: output << "cmp "; break; + case 11: output << "shr1 "; break; + case 12: output << "shl1 "; break; + case 13: output << "shl2 "; break; + case 14: output << "shl4 "; break; + case 15: output << "xchg "; break; + } + + if(alu < 8) { + switch(pselect) { + case 0: output << "ram,"; break; + case 1: output << "idb,"; break; + case 2: output << "m,"; break; + case 3: output << "n,"; break; + } + } + + switch(asl) { + case 0: output << "a"; break; + case 1: output << "b"; break; + } + + if(dst) { + output << "\n mov "; + + switch(src) { + case 0: output << "trb,"; break; + case 1: output << "a,"; break; + case 2: output << "b,"; break; + case 3: output << "tr,"; break; + case 4: output << "dp,"; break; + case 5: output << "rp,"; break; + case 6: output << "ro,"; break; + case 7: output << "sgn,"; break; + case 8: output << "dr,"; break; + case 9: output << "drnf,"; break; + case 10: output << "sr,"; break; + case 11: output << "sim,"; break; + case 12: output << "sil,"; break; + case 13: output << "k,"; break; + case 14: output << "l,"; break; + case 15: output << "mem,"; break; + } + + switch(dst) { + case 0: output << "non"; break; + case 1: output << "a"; break; + case 2: output << "b"; break; + case 3: output << "tr"; break; + case 4: output << "dp"; break; + case 5: output << "rp"; break; + case 6: output << "dr"; break; + case 7: output << "sr"; break; + case 8: output << "sol"; break; + case 9: output << "som"; break; + case 10: output << "k"; break; + case 11: output << "klr"; break; + case 12: output << "klm"; break; + case 13: output << "l"; break; + case 14: output << "trb"; break; + case 15: output << "mem"; break; + } + } + + if(dpl) { + switch(dpl) { + case 0: output << "\n dpnop"; break; + case 1: output << "\n dpinc"; break; + case 2: output << "\n dpdec"; break; + case 3: output << "\n dpclr"; break; + } + } + + if(dphm) { + switch(dphm) { + case 0: output << "\n m0"; break; + case 1: output << "\n m1"; break; + case 2: output << "\n m2"; break; + case 3: output << "\n m3"; break; + case 4: output << "\n m4"; break; + case 5: output << "\n m5"; break; + case 6: output << "\n m6"; break; + case 7: output << "\n m7"; break; + case 8: output << "\n m8"; break; + case 9: output << "\n m9"; break; + case 10: output << "\n ma"; break; + case 11: output << "\n mb"; break; + case 12: output << "\n mc"; break; + case 13: output << "\n md"; break; + case 14: output << "\n me"; break; + case 15: output << "\n mf"; break; + } + } + + if(rpdcr == 1) { + output << "\n rpdec"; + } + + if(type == 1) { + output << "\n ret"; + } + } + + if(type == 2) { //JP + uint9 brch = opcode >> 13; + uint11 na = opcode >> 2; + + switch(brch) { + case 0x080: output << "jnca "; break; + case 0x082: output << "jca "; break; + case 0x084: output << "jncb "; break; + case 0x086: output << "jcb "; break; + case 0x088: output << "jnza "; break; + case 0x08a: output << "jza "; break; + case 0x08c: output << "jnzb "; break; + case 0x08e: output << "jzb "; break; + case 0x090: output << "jnova0 "; break; + case 0x092: output << "jova0 "; break; + case 0x094: output << "jnovb0 "; break; + case 0x096: output << "jovb0 "; break; + case 0x098: output << "jnova1 "; break; + case 0x09a: output << "jova1 "; break; + case 0x09c: output << "jnovb1 "; break; + case 0x09e: output << "jovb1 "; break; + case 0x0a0: output << "jnsa0 "; break; + case 0x0a2: output << "jsa0 "; break; + case 0x0a4: output << "jnsb0 "; break; + case 0x0a6: output << "jsb0 "; break; + case 0x0a8: output << "jnsa1 "; break; + case 0x0aa: output << "jsa1 "; break; + case 0x0ac: output << "jnsb1 "; break; + case 0x0ae: output << "jsb1 "; break; + case 0x0b0: output << "jdpl0 "; break; + case 0x0b1: output << "jdpln0 "; break; + case 0x0b2: output << "jdplf "; break; + case 0x0b3: output << "jdplnf "; break; + case 0x0b4: output << "jnsiak "; break; + case 0x0b6: output << "jsiak "; break; + case 0x0b8: output << "jnsoak "; break; + case 0x0ba: output << "jsoak "; break; + case 0x0bc: output << "jnrqm "; break; + case 0x0be: output << "jrqm "; break; + case 0x100: output << "jmp "; break; + case 0x140: output << "call "; break; + default: output << "?????? "; break; + } + + output << "$" << strhex<3>(na); + } + + if(type == 3) { //LD + output << "ld "; + uint16 id = opcode >> 6; + uint4 dst = opcode >> 0; + + output << "$" << strhex<4>(id) << ","; + + switch(dst) { + case 0: output << "non"; break; + case 1: output << "a"; break; + case 2: output << "b"; break; + case 3: output << "tr"; break; + case 4: output << "dp"; break; + case 5: output << "rp"; break; + case 6: output << "dr"; break; + case 7: output << "sr"; break; + case 8: output << "sol"; break; + case 9: output << "som"; break; + case 10: output << "k"; break; + case 11: output << "klr"; break; + case 12: output << "klm"; break; + case 13: output << "l"; break; + case 14: output << "trb"; break; + case 15: output << "mem"; break; + } + } + + return output; +} diff --git a/bsnes/snes/chip/upd77c25/upd77c25.cpp b/bsnes/snes/chip/upd77c25/upd77c25.cpp new file mode 100755 index 00000000..2a15b86b --- /dev/null +++ b/bsnes/snes/chip/upd77c25/upd77c25.cpp @@ -0,0 +1,507 @@ +//NEC uPD77C25 emulation core +//author: byuu +//license: public domain + +#include + +#define UPD77C25_CPP +namespace SNES { + +#include "disassembler.cpp" + +UPD77C25 upd77c25; +UPD77C25SR upd77c25sr; +UPD77C25DR upd77c25dr; + +void UPD77C25::Enter() { upd77c25.enter(); } + +void UPD77C25::enter() { + while(true) { + //print(disassemble(regs.pc), "\n"); + + uint24 opcode = programROM[regs.pc++]; + switch(opcode >> 22) { + case 0: exec_op(opcode); break; + case 1: exec_rt(opcode); break; + case 2: exec_jp(opcode); break; + case 3: exec_ld(opcode); break; + } + + uint31 result = regs.k * regs.l; //sign + 30-bit result + regs.m = result >> 15; //store sign + top 15-bits + regs.n = result << 1; //store low 15-bits + zero + + step(1); + synchronize_cpu(); + } +} + +void UPD77C25::exec_op(uint24 opcode) { + uint2 pselect = opcode >> 20; //p-select + uint4 alu = opcode >> 16; //ALU + uint1 asl = opcode >> 15; //ASL + uint2 dpl = opcode >> 13; //DPl + uint4 dphm = opcode >> 9; //DPhM + uint1 rpdcr = opcode >> 8; //RP decrement + uint4 src = opcode >> 4; //source + uint4 dst = opcode >> 0; //destination + + unsigned p, q, r; + Flag flag; + + switch(pselect) { + case 0: p = dataRAM[regs.dp]; break; + case 1: p = regs.idb; break; + case 2: p = regs.m; break; + case 3: p = regs.n; break; + } + + switch(asl) { + case 0: q = regs.a; flag = regs.flaga; break; + case 1: q = regs.b; flag = regs.flagb; break; + } + + switch(alu) { + case 0: { //NOP + break; + } + + case 1: { //OR + r = q | p; + flag.s0 = r & 0x8000; + flag.c = 0; + flag.z = !r; + flag.ov1 = 0; + flag.ov0 = 0; + break; + } + + case 2: { //AND + r = q & p; + flag.s0 = r & 0x8000; + flag.c = 0; + flag.z = !r; + flag.ov1 = 0; + flag.ov0 = 0; + break; + } + + case 3: { //XOR + r = q ^ p; + flag.s0 = r & 0x8000; + flag.c = 0; + flag.z = !r; + flag.ov1 = 0; + flag.ov0 = 0; + break; + } + + case 4: { //SUB + r = q - p; + bool pov = (((p | q) & 0x8000) == 0x0000) && ((r & 0x8000) == 0x8000); + bool nov = (((p & q) & 0x8000) == 0x8000) && ((r & 0x8000) == 0x0000); + flag.s1 = nov; + flag.s0 = r & 0x8000; + flag.c = r > 0xffff; + flag.z = !r; + //flag.ov1 = ?; + flag.ov0 = pov | nov; + break; + } + + case 5: { //ADD + r = q + p; + bool pov = (((p | q) & 0x8000) == 0x0000) && ((r & 0x8000) == 0x8000); + bool nov = (((p & q) & 0x8000) == 0x8000) && ((r & 0x8000) == 0x0000); + flag.s1 = nov; + flag.s0 = r & 0x8000; + flag.c = r > 0xffff; + flag.z = !r; + //flag.ov1 = ?; + flag.ov0 = pov | nov; + break; + } + + case 6: { //SBB + r = q - p - flag.c; + bool pov = (((p | q) & 0x8000) == 0x0000) && ((r & 0x8000) == 0x8000); + bool nov = (((p & q) & 0x8000) == 0x8000) && ((r & 0x8000) == 0x0000); + flag.s1 = nov; + flag.s0 = r & 0x8000; + flag.c = r > 0xffff; + flag.z = !r; + //flag.ov1 = ?; + flag.ov0 = pov | nov; + break; + } + + case 7: { //ADC + r = q + p + flag.c; + bool pov = (((p | q) & 0x8000) == 0x0000) && ((r & 0x8000) == 0x8000); + bool nov = (((p & q) & 0x8000) == 0x8000) && ((r & 0x8000) == 0x0000); + flag.s1 = nov; + flag.s0 = r & 0x8000; + flag.c = r > 0xffff; + flag.z = !r; + //flag.ov1 = ?; + flag.ov0 = pov | nov; + break; + } + + case 8: { //DEC + r = q - 1; + bool pov = (((p | q) & 0x8000) == 0x0000) && ((r & 0x8000) == 0x8000); + bool nov = (((p & q) & 0x8000) == 0x8000) && ((r & 0x8000) == 0x0000); + flag.s1 = nov; + flag.s0 = r & 0x8000; + flag.c = r > 0xffff; + flag.z = !r; + //flag.ov1 = ?; + flag.ov0 = pov | nov; + break; + } + + case 9: { //INC + r = q + 1; + bool pov = (((p | q) & 0x8000) == 0x0000) && ((r & 0x8000) == 0x8000); + bool nov = (((p & q) & 0x8000) == 0x8000) && ((r & 0x8000) == 0x0000); + flag.s1 = nov; + flag.s0 = r & 0x8000; + flag.c = r > 0xffff; + flag.z = !r; + //flag.ov1 = ?; + flag.ov0 = pov | nov; + break; + } + + case 10: { //CMP (complement) + r = !q; + flag.s0 = r & 0x8000; + flag.c = 0; + flag.z = !r; + flag.ov1 = 0; + flag.ov0 = 0; + break; + } + + case 11: { //SHR1 + r = q >> 1; + flag.s0 = r & 0x8000; + flag.c = q & 1; + flag.z = !r; + flag.ov1 = 0; + flag.ov0 = 0; + break; + } + + case 12: { //SHL1 + r = q << 1; + flag.s0 = r & 0x8000; + flag.c = r & 0x8000; + flag.z = !r; + flag.ov1 = 0; + flag.ov0 = 0; + break; + } + + case 13: { //SHL2 + r = q << 2; + flag.s0 = r & 0x8000; + flag.c = 0; + flag.z = !r; + flag.ov1 = 0; + flag.ov0 = 0; + break; + } + + case 14: { //SHL4 + r = q << 4; + flag.s0 = r & 0x8000; + flag.c = 0; + flag.z = !r; + flag.ov1 = 0; + flag.ov0 = 0; + break; + } + + case 15: { //XCHG + r = (q & 0xff00) | (p & 0x00ff); + flag.s0 = r & 0x8000; + flag.c = 0; + flag.z = !r; + flag.ov1 = 0; + flag.ov0 = 0; + break; + } + } + + switch(src) { + case 0: regs.idb = regs.trb; break; + case 1: regs.idb = regs.a; break; + case 2: regs.idb = regs.b; break; + case 3: regs.idb = regs.tr; break; + case 4: regs.idb = regs.dp; break; + case 5: regs.idb = regs.rp; break; + case 6: regs.idb = dataROM[regs.rp]; break; + case 7: regs.idb = regs.flaga.s1 ? 0x7fff : 0x8000; break; + case 8: regs.idb = regs.dr; regs.sr.rqm = 1; break; + case 9: regs.idb = regs.dr; break; + case 10: regs.idb = regs.sr; break; + //case 11: regs.idb = regs.sim; break; + //case 12: regs.idb = regs.sil; break; + case 13: regs.idb = regs.k; break; + case 14: regs.idb = regs.l; break; + case 15: regs.idb = dataRAM[regs.dp]; break; + default: print("OP: unhandled src case ", strhex<2>(src), "\n"); break; + } + + switch(dst) { + case 0: break; + case 1: regs.a = regs.idb; break; + case 2: regs.b = regs.idb; break; + case 3: regs.tr = regs.idb; break; + case 4: regs.dp = regs.idb; break; + case 5: regs.rp = regs.idb; break; + case 6: regs.dr = regs.idb; regs.sr.rqm = 1; break; + case 7: regs.sr = (regs.sr & 0x9000) | (regs.idb & ~0x9000); break; + //case 8: regs.sol = regs.idb; break; + //case 9: regs.som = regs.idb; break; + case 10: regs.k = regs.idb; break; + case 11: regs.k = regs.idb; regs.l = dataROM[regs.rp]; break; + case 12: regs.k = dataRAM[regs.dp | 0x40]; regs.l = regs.idb; break; + case 13: regs.l = regs.idb; break; + case 14: regs.trb = regs.idb; break; + case 15: dataRAM[regs.dp] = regs.idb; break; + default: print("OP: unhandled dst case ", strhex<2>(dst), "\n"); break; + } + + switch(asl) { + case 0: regs.a = r; regs.flaga = flag; break; + case 1: regs.b = r; regs.flagb = flag; break; + } + + switch(dpl) { + case 0: break; //DPNOP + case 1: regs.dp = (regs.dp & 0xf0) + ((regs.dp + 1) & 0x0f); break; //DPINC + case 2: regs.dp = (regs.dp & 0xf0) + ((regs.dp - 1) & 0x0f); break; //DPDEC + case 3: regs.dp = (regs.dp & 0xf0); break; //DPCLR + } + + regs.dp ^= dphm << 4; + + switch(rpdcr) { + case 0: break; //RPNOP + case 1: regs.rp--; break; //RPDEC + } +} + +void UPD77C25::exec_rt(uint24 opcode) { + exec_op(opcode); + stack_pull(); +} + +void UPD77C25::exec_jp(uint24 opcode) { + uint9 brch = opcode >> 13; //branch + uint11 na = opcode >> 2; //next address + + bool r = false; + + switch(brch) { + case 0x080: r = (regs.flaga.c == 0); break; //JNCA + case 0x082: r = (regs.flaga.c == 1); break; //JCA + case 0x084: r = (regs.flagb.c == 0); break; //JNCB + case 0x086: r = (regs.flagb.c == 1); break; //JCB + case 0x088: r = (regs.flaga.z == 0); break; //JNZA + case 0x08a: r = (regs.flaga.z == 1); break; //JZA + case 0x08c: r = (regs.flagb.z == 0); break; //JNZB + case 0x08e: r = (regs.flagb.z == 1); break; //JZB + case 0x090: r = (regs.flaga.ov0 == 0); break; //JNOVA0 + case 0x092: r = (regs.flaga.ov0 == 1); break; //JOVA0 + case 0x094: r = (regs.flagb.ov0 == 0); break; //JNOVB0 + case 0x096: r = (regs.flagb.ov0 == 1); break; //JOVB0 + case 0x098: r = (regs.flaga.ov1 == 0); break; //JNOVA1 + case 0x09a: r = (regs.flaga.ov1 == 1); break; //JOVA1 + case 0x09c: r = (regs.flagb.ov1 == 0); break; //JNOVB1 + case 0x09e: r = (regs.flagb.ov1 == 1); break; //JOVB1 + case 0x0a0: r = (regs.flaga.s0 == 0); break; //JNSA0 + case 0x0a2: r = (regs.flaga.s0 == 1); break; //JSA0 + case 0x0a4: r = (regs.flagb.s0 == 0); break; //JNSB0 + case 0x0a6: r = (regs.flagb.s0 == 1); break; //JSB0 + case 0x0a8: r = (regs.flaga.s1 == 0); break; //JNSA1 + case 0x0aa: r = (regs.flaga.s1 == 1); break; //JSA1 + case 0x0ac: r = (regs.flagb.s1 == 0); break; //JNSB1 + case 0x0ae: r = (regs.flagb.s1 == 1); break; //JSB1 + + case 0x0b0: r = (regs.dp & 0x0f) == 0x00; break; //JDPL0 + case 0x0b1: r = (regs.dp & 0x0f) != 0x00; break; //JDPLN0 + case 0x0b2: r = (regs.dp & 0x0f) == 0x0f; break; //JDPLF + case 0x0b3: r = (regs.dp & 0x0f) != 0x0f; break; //JDPLNF + + case 0x0b4: r = (regs.siack == 0); break; //JNSIAK + case 0x0b6: r = (regs.siack == 1); break; //JSIAK + + case 0x0b8: r = (regs.soack == 0); break; //JNSOAK + case 0x0ba: r = (regs.soack == 1); break; //JSOAK + + case 0x0bc: r = (regs.sr.rqm == 0); break; //JNRQM + case 0x0be: r = (regs.sr.rqm == 1); break; //JRQM + + case 0x100: r = true; break; //JMP + case 0x140: r = true; stack_push(); break; //CALL + } + + if(r) regs.pc = na; +} + +void UPD77C25::exec_ld(uint24 opcode) { + uint16 id = opcode >> 6; //immediate data + uint4 dst = opcode >> 0; //destination + + switch(dst) { + case 0: break; + case 1: regs.a = id; break; + case 2: regs.b = id; break; + case 3: regs.tr = id; break; + case 4: regs.dp = id; break; + case 5: regs.rp = id; break; + case 6: regs.dr = id; regs.sr.rqm = 1; break; + case 7: regs.sr = (regs.sr & 0x9000) | (id & ~0x9000); break; + //case 8: regs.sol = id; break; + //case 9: regs.som = id; break; + case 10: regs.k = id; break; + case 11: regs.k = regs.idb; regs.l = dataROM[regs.rp]; break; + //case 12: regs.klm = id; break; + case 13: regs.l = id; break; + case 14: regs.trb = id; break; + case 15: dataRAM[regs.dp] = id; break; + default: print("LD: unhandled dst case ", strhex<2>(dst), "\n"); break; + } +} + +void UPD77C25::stack_push() { + regs.stack[3] = regs.stack[2]; + regs.stack[2] = regs.stack[1]; + regs.stack[1] = regs.stack[0]; + regs.stack[0] = regs.pc; +} + +void UPD77C25::stack_pull() { + regs.pc = regs.stack[0]; + regs.stack[0] = regs.stack[1]; + regs.stack[1] = regs.stack[2]; + regs.stack[2] = regs.stack[3]; + regs.stack[3] = 0x000; +} + +uint8 UPD77C25::read(bool mode) { + if(mode == 0) return (unsigned)regs.sr >> 8; + + if(regs.sr.drc == 0) { + //16-bit + if(regs.sr.drs == 0) { + regs.sr.drs = 1; + return regs.dr >> 0; + } else { + regs.sr.rqm = 0; + regs.sr.drs = 0; + return regs.dr >> 8; + } + } else { + //8-bit + regs.sr.rqm = 0; + return regs.dr >> 0; + } +} + +void UPD77C25::write(bool mode, uint8 data) { + if(mode == 0) return; + + if(regs.sr.drc == 0) { + //16-bit + if(regs.sr.drs == 0) { + regs.sr.drs = 1; + regs.dr = (regs.dr & 0xff00) | (data << 0); + } else { + regs.sr.rqm = 0; + regs.sr.drs = 0; + regs.dr = (data << 8) | (regs.dr & 0x00ff); + } + } else { + //8-bit + regs.sr.rqm = 0; + regs.dr = (regs.dr & 0xff00) | (data << 0); + } +} + +void UPD77C25::init() { +} + +void UPD77C25::enable() { +} + +void UPD77C25::power() { + for(unsigned i = 0; i < 2048; i++) programROM[i] = 0x000000; + for(unsigned i = 0; i < 1024; i++) dataROM[i] = 0x0000; + for(unsigned i = 0; i < 256; i++) dataRAM[i] = 0x0000; + + string filename; + file fp; + + filename = string(dir(cartridge.basename()), program); + if(fp.open(filename, file::mode::read)) { + for(unsigned i = 0; i < 2048; i++) { + programROM[i] |= fp.read() << 16; + programROM[i] |= fp.read() << 8; + programROM[i] |= fp.read() << 0; + fp.read(); //skip 24-bit -> 32-bit padding + } + fp.close(); + } + + filename = string(dir(cartridge.basename()), data); + if(fp.open(filename, file::mode::read)) { + for(unsigned i = 0; i < 1024; i++) { + dataROM[i] |= fp.read() << 8; + dataROM[i] |= fp.read() << 0; + } + fp.close(); + } + + #if 0 + fp.open("/home/byuu/Desktop/disassembly.txt", file::mode::write); + for(unsigned i = 0; i < 2048; i++) { + string output = disassemble(i); + fp.print(output); + fp.print("\n"); + } + fp.close(); + #endif + + reset(); +} + +void UPD77C25::reset() { + create(UPD77C25::Enter, 8 * 1024 * 1024); //8.192MHz + + regs.pc = 0x000; + regs.stack[0] = 0x000; + regs.stack[1] = 0x000; + regs.stack[2] = 0x000; + regs.stack[3] = 0x000; + regs.flaga = 0x00; + regs.flagb = 0x00; + regs.sr = 0x0000; + regs.rp = 0x3ff; + regs.siack = 0; + regs.soack = 0; + + regs.sr.rqm = 1; +} + +uint8 UPD77C25SR::read(unsigned) { return upd77c25.read(0); } +void UPD77C25SR::write(unsigned, uint8 data) { upd77c25.write(0, data); } + +uint8 UPD77C25DR::read(unsigned) { return upd77c25.read(1); } +void UPD77C25DR::write(unsigned, uint8 data) { upd77c25.write(1, data); } + +} diff --git a/bsnes/snes/chip/upd77c25/upd77c25.hpp b/bsnes/snes/chip/upd77c25/upd77c25.hpp new file mode 100755 index 00000000..ae49cdad --- /dev/null +++ b/bsnes/snes/chip/upd77c25/upd77c25.hpp @@ -0,0 +1,97 @@ +class UPD77C25 : public Coprocessor { +public: + static void Enter(); + void enter(); + void init(); + void enable(); + void power(); + void reset(); + + string disassemble(uint11 ip); + + string program; + string data; + +private: + uint24 programROM[2048]; + uint16 dataROM[1024]; + uint16 dataRAM[256]; + + struct Flag { + bool s1, s0, c, z, ov1, ov0; + + inline operator unsigned() const { + return (s1 << 5) + (s0 << 4) + (c << 3) + (z << 2) + (ov1 << 1) + (ov0 << 0); + } + + inline unsigned operator=(unsigned d) { + s1 = d & 0x20; s0 = d & 0x10; c = d & 0x08; z = d & 0x04; ov1 = d & 0x02; ov0 = d & 0x01; + return d; + } + }; + + struct Status { + bool rqm, usf1, usf0, drs, dma, drc, soc, sic, ei, p1, p0; + + inline operator unsigned() const { + return (rqm << 15) + (usf1 << 14) + (usf0 << 13) + (drs << 12) + + (dma << 11) + (drc << 10) + (soc << 9) + (sic << 8) + + (ei << 7) + (p1 << 1) + (p0 << 0); + } + + inline unsigned operator=(unsigned d) { + rqm = d & 0x8000; usf1 = d & 0x4000; usf0 = d & 0x2000; drs = d & 0x1000; + dma = d & 0x0800; drc = d & 0x0400; soc = d & 0x0200; sic = d & 0x0100; + ei = d & 0x0080; p1 = d & 0x0002; p0 = d & 0x0001; + return d; + } + }; + + struct Regs { + uint11 pc; //program counter + uint11 stack[4]; //LIFO + uint10 rp; //ROM pointer + uint8 dp; //data pointer + uint16 k; + uint16 l; + uint16 m; + uint16 n; + uint16 a; //accumulator + uint16 b; //accumulator + Flag flaga; + Flag flagb; + uint16 tr; //temporary registers + uint16 trb; + Status sr; //status register + uint16 dr; //data register + bool siack; + bool soack; + uint16 idb; + } regs; + + void exec_op(uint24 opcode); + void exec_rt(uint24 opcode); + void exec_jp(uint24 opcode); + void exec_ld(uint24 opcode); + void stack_push(); + void stack_pull(); + uint8 read(bool mode); + void write(bool mode, uint8 data); + + friend class UPD77C25SR; + friend class UPD77C25DR; +}; + +class UPD77C25SR : public Memory { + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); +}; + +class UPD77C25DR : public Memory { + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); +}; + +extern UPD77C25 upd77c25; +extern UPD77C25SR upd77c25sr; +extern UPD77C25DR upd77c25dr; diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index 3ed7467b..afbfd736 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "072.07"; + static const char Version[] = "072.09"; static const unsigned SerializerVersion = 14; } } @@ -48,12 +48,17 @@ namespace SNES { typedef uint32_t uint32; typedef uint64_t uint64; + typedef uint_t<1> uint1; typedef uint_t<2> uint2; typedef uint_t<3> uint3; + typedef uint_t<4> uint4; + typedef uint_t<6> uint6; typedef uint_t<9> uint9; typedef uint_t<10> uint10; + typedef uint_t<11> uint11; typedef uint_t<17> uint17; typedef uint_t<24> uint24; + typedef uint_t<31> uint31; struct Processor { cothread_t thread; diff --git a/bsnes/snes/system/system.cpp b/bsnes/snes/system/system.cpp index 24dfe3af..95b1c8fb 100755 --- a/bsnes/snes/system/system.cpp +++ b/bsnes/snes/system/system.cpp @@ -71,6 +71,7 @@ void System::init(Interface *interface_) { supergameboy.init(); superfx.init(); sa1.init(); + upd77c25.init(); bsxbase.init(); bsxcart.init(); bsxflash.init(); @@ -126,6 +127,7 @@ void System::power() { if(cartridge.has_superfx()) superfx.enable(); if(cartridge.has_sa1()) sa1.enable(); + if(cartridge.has_upd77c25()) upd77c25.enable(); if(cartridge.has_srtc()) srtc.enable(); if(cartridge.has_sdd1()) sdd1.enable(); if(cartridge.has_spc7110()) spc7110.enable(); @@ -153,6 +155,7 @@ void System::power() { if(cartridge.has_superfx()) superfx.power(); if(cartridge.has_sa1()) sa1.power(); + if(cartridge.has_upd77c25()) upd77c25.power(); if(cartridge.has_srtc()) srtc.power(); if(cartridge.has_sdd1()) sdd1.power(); if(cartridge.has_spc7110()) spc7110.power(); @@ -171,6 +174,7 @@ void System::power() { if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&supergameboy); if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx); if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1); + if(cartridge.has_upd77c25()) cpu.coprocessors.append(&upd77c25); if(cartridge.has_msu1()) cpu.coprocessors.append(&msu1); if(cartridge.has_serial()) cpu.coprocessors.append(&serial); @@ -194,6 +198,7 @@ void System::reset() { if(cartridge.has_superfx()) superfx.reset(); if(cartridge.has_sa1()) sa1.reset(); + if(cartridge.has_upd77c25()) upd77c25.reset(); if(cartridge.has_srtc()) srtc.reset(); if(cartridge.has_sdd1()) sdd1.reset(); if(cartridge.has_spc7110()) spc7110.reset();