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:
Tim Allen 2010-12-17 21:54:28 +11:00
parent 26643a43de
commit 3bd29088d1
11 changed files with 864 additions and 3 deletions

View File

@ -1,6 +1,6 @@
include nall/Makefile include nall/Makefile
snes := snes snes := snes
profile := performance profile := compatibility
ui := ui-phoenix ui := ui-phoenix
# compiler # compiler

View File

@ -3,7 +3,7 @@ snes_objects += snes-system
snes_objects += snes-cartridge snes-cheat snes_objects += snes-cartridge snes-cheat
snes_objects += snes-memory snes-cpucore snes-smpcore snes_objects += snes-memory snes-cpucore snes-smpcore
snes_objects += snes-cpu snes-smp snes-dsp snes-ppu 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-bsx snes-srtc snes-sdd1 snes-spc7110
snes_objects += snes-cx4 snes-dsp1 snes-dsp2 snes-dsp3 snes-dsp4 snes_objects += snes-cx4 snes-dsp1 snes-dsp2 snes-dsp3 snes-dsp4
snes_objects += snes-obc1 snes-st0010 snes-st0011 snes-st0018 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-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-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-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-bsx.o : $(snes)/chip/bsx/bsx.cpp $(snes)/chip/bsx/*
obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/* obj/snes-srtc.o : $(snes)/chip/srtc/srtc.cpp $(snes)/chip/srtc/*
obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/* obj/snes-sdd1.o : $(snes)/chip/sdd1/sdd1.cpp $(snes)/chip/sdd1/*

View File

@ -31,6 +31,7 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) {
has_bsx_slot = false; has_bsx_slot = false;
has_superfx = false; has_superfx = false;
has_sa1 = false; has_sa1 = false;
has_upd77c25 = false;
has_srtc = false; has_srtc = false;
has_sdd1 = false; has_sdd1 = false;
has_spc7110 = false; has_spc7110 = false;

View File

@ -37,6 +37,7 @@ public:
readonly<bool> has_bsx_slot; readonly<bool> has_bsx_slot;
readonly<bool> has_superfx; readonly<bool> has_superfx;
readonly<bool> has_sa1; readonly<bool> has_sa1;
readonly<bool> has_upd77c25;
readonly<bool> has_srtc; readonly<bool> has_srtc;
readonly<bool> has_sdd1; readonly<bool> has_sdd1;
readonly<bool> has_spc7110; readonly<bool> has_spc7110;
@ -88,6 +89,7 @@ private:
void xml_parse_ram(xml_element&); void xml_parse_ram(xml_element&);
void xml_parse_superfx(xml_element&); void xml_parse_superfx(xml_element&);
void xml_parse_sa1(xml_element&); void xml_parse_sa1(xml_element&);
void xml_parse_upd77c25(xml_element&);
void xml_parse_bsx(xml_element&); void xml_parse_bsx(xml_element&);
void xml_parse_sufamiturbo(xml_element&); void xml_parse_sufamiturbo(xml_element&);
void xml_parse_supergameboy(xml_element&); void xml_parse_supergameboy(xml_element&);

View File

@ -34,6 +34,7 @@ void Cartridge::parse_xml_cartridge(const char *data) {
if(node.name == "ram") xml_parse_ram(node); if(node.name == "ram") xml_parse_ram(node);
if(node.name == "superfx") xml_parse_superfx(node); if(node.name == "superfx") xml_parse_superfx(node);
if(node.name == "sa1") xml_parse_sa1(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 == "bsx") xml_parse_bsx(node);
if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node); if(node.name == "sufamiturbo") xml_parse_sufamiturbo(node);
if(node.name == "supergameboy") xml_parse_supergameboy(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) { void Cartridge::xml_parse_bsx(xml_element &root) {
if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return; if(mode != Mode::BsxSlotted && mode != Mode::Bsx) return;

View File

@ -6,6 +6,7 @@ struct Coprocessor : Processor {
#include <chip/supergameboy/supergameboy.hpp> #include <chip/supergameboy/supergameboy.hpp>
#include <chip/superfx/superfx.hpp> #include <chip/superfx/superfx.hpp>
#include <chip/sa1/sa1.hpp> #include <chip/sa1/sa1.hpp>
#include <chip/upd77c25/upd77c25.hpp>
#include <chip/bsx/bsx.hpp> #include <chip/bsx/bsx.hpp>
#include <chip/srtc/srtc.hpp> #include <chip/srtc/srtc.hpp>
#include <chip/sdd1/sdd1.hpp> #include <chip/sdd1/sdd1.hpp>

View File

@ -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;
}

View File

@ -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); }
}

View File

@ -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;

View File

@ -1,7 +1,7 @@
namespace SNES { namespace SNES {
namespace Info { namespace Info {
static const char Name[] = "bsnes"; static const char Name[] = "bsnes";
static const char Version[] = "072.07"; static const char Version[] = "072.09";
static const unsigned SerializerVersion = 14; static const unsigned SerializerVersion = 14;
} }
} }
@ -48,12 +48,17 @@ namespace SNES {
typedef uint32_t uint32; typedef uint32_t uint32;
typedef uint64_t uint64; typedef uint64_t uint64;
typedef uint_t<1> uint1;
typedef uint_t<2> uint2; typedef uint_t<2> uint2;
typedef uint_t<3> uint3; typedef uint_t<3> uint3;
typedef uint_t<4> uint4;
typedef uint_t<6> uint6;
typedef uint_t<9> uint9; typedef uint_t<9> uint9;
typedef uint_t<10> uint10; typedef uint_t<10> uint10;
typedef uint_t<11> uint11;
typedef uint_t<17> uint17; typedef uint_t<17> uint17;
typedef uint_t<24> uint24; typedef uint_t<24> uint24;
typedef uint_t<31> uint31;
struct Processor { struct Processor {
cothread_t thread; cothread_t thread;

View File

@ -71,6 +71,7 @@ void System::init(Interface *interface_) {
supergameboy.init(); supergameboy.init();
superfx.init(); superfx.init();
sa1.init(); sa1.init();
upd77c25.init();
bsxbase.init(); bsxbase.init();
bsxcart.init(); bsxcart.init();
bsxflash.init(); bsxflash.init();
@ -126,6 +127,7 @@ void System::power() {
if(cartridge.has_superfx()) superfx.enable(); if(cartridge.has_superfx()) superfx.enable();
if(cartridge.has_sa1()) sa1.enable(); if(cartridge.has_sa1()) sa1.enable();
if(cartridge.has_upd77c25()) upd77c25.enable();
if(cartridge.has_srtc()) srtc.enable(); if(cartridge.has_srtc()) srtc.enable();
if(cartridge.has_sdd1()) sdd1.enable(); if(cartridge.has_sdd1()) sdd1.enable();
if(cartridge.has_spc7110()) spc7110.enable(); if(cartridge.has_spc7110()) spc7110.enable();
@ -153,6 +155,7 @@ void System::power() {
if(cartridge.has_superfx()) superfx.power(); if(cartridge.has_superfx()) superfx.power();
if(cartridge.has_sa1()) sa1.power(); if(cartridge.has_sa1()) sa1.power();
if(cartridge.has_upd77c25()) upd77c25.power();
if(cartridge.has_srtc()) srtc.power(); if(cartridge.has_srtc()) srtc.power();
if(cartridge.has_sdd1()) sdd1.power(); if(cartridge.has_sdd1()) sdd1.power();
if(cartridge.has_spc7110()) spc7110.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.mode() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&supergameboy);
if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx); if(cartridge.has_superfx()) cpu.coprocessors.append(&superfx);
if(cartridge.has_sa1()) cpu.coprocessors.append(&sa1); 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_msu1()) cpu.coprocessors.append(&msu1);
if(cartridge.has_serial()) cpu.coprocessors.append(&serial); if(cartridge.has_serial()) cpu.coprocessors.append(&serial);
@ -194,6 +198,7 @@ void System::reset() {
if(cartridge.has_superfx()) superfx.reset(); if(cartridge.has_superfx()) superfx.reset();
if(cartridge.has_sa1()) sa1.reset(); if(cartridge.has_sa1()) sa1.reset();
if(cartridge.has_upd77c25()) upd77c25.reset();
if(cartridge.has_srtc()) srtc.reset(); if(cartridge.has_srtc()) srtc.reset();
if(cartridge.has_sdd1()) sdd1.reset(); if(cartridge.has_sdd1()) sdd1.reset();
if(cartridge.has_spc7110()) spc7110.reset(); if(cartridge.has_spc7110()) spc7110.reset();