mirror of https://github.com/bsnes-emu/bsnes.git
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: <?xml version='1.0' encoding='UTF-8'?> <cartridge region='NTSC'> <rom> <map mode='shadow' address='00-3f:8000-ffff'/> <map mode='linear' address='40-7f:0000-ffff'/> <map mode='shadow' address='80-bf:8000-ffff'/> <map mode='linear' address='c0-ff:0000-ffff'/> </rom> <ram size='800'> <map mode='linear' address='20-3f:6000-7fff'/> <map mode='linear' address='a0-bf:6000-7fff'/> <map mode='linear' address='70-7f:0000-ffff'/> </ram> <upd77c25 program="dsp1b-program.bin" data="dsp1b-data.bin"> <dr> <map address='00-1f:6000-6fff'/> <map address='80-9f:6000-6fff'/> </dr> <sr> <map address='00-1f:7000-7fff'/> <map address='80-9f:7000-7fff'/> </sr> </upd77c25> </cartridge> 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.
This commit is contained in:
parent
26643a43de
commit
3bd29088d1
|
@ -1,6 +1,6 @@
|
|||
include nall/Makefile
|
||||
snes := snes
|
||||
profile := performance
|
||||
profile := compatibility
|
||||
ui := ui-phoenix
|
||||
|
||||
# compiler
|
||||
|
|
|
@ -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/*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -37,6 +37,7 @@ public:
|
|||
readonly<bool> has_bsx_slot;
|
||||
readonly<bool> has_superfx;
|
||||
readonly<bool> has_sa1;
|
||||
readonly<bool> has_upd77c25;
|
||||
readonly<bool> has_srtc;
|
||||
readonly<bool> has_sdd1;
|
||||
readonly<bool> 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&);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ struct Coprocessor : Processor {
|
|||
#include <chip/supergameboy/supergameboy.hpp>
|
||||
#include <chip/superfx/superfx.hpp>
|
||||
#include <chip/sa1/sa1.hpp>
|
||||
#include <chip/upd77c25/upd77c25.hpp>
|
||||
#include <chip/bsx/bsx.hpp>
|
||||
#include <chip/srtc/srtc.hpp>
|
||||
#include <chip/sdd1/sdd1.hpp>
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,507 @@
|
|||
//NEC uPD77C25 emulation core
|
||||
//author: byuu
|
||||
//license: public domain
|
||||
|
||||
#include <snes.hpp>
|
||||
|
||||
#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); }
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue