From 3bb6889efd95ee301ea2b46834e013c12a83c7f6 Mon Sep 17 00:00:00 2001 From: Themaister Date: Sun, 26 Jun 2011 13:43:01 +0200 Subject: [PATCH] v80 --- .gitignore | 1 + nall/string/base.hpp | 10 + nall/string/core.hpp | 2 + snes/Makefile | 26 +- snes/alt/cpu/cpu.cpp | 10 +- snes/alt/cpu/cpu.hpp | 4 +- snes/alt/cpu/mmio.cpp | 10 +- snes/alt/cpu/timing.cpp | 17 +- snes/cartridge/cartridge.cpp | 1 - snes/cartridge/cartridge.hpp | 4 +- snes/cartridge/xml.cpp | 181 +++++------ snes/cheat/cheat.cpp | 26 +- snes/cheat/cheat.hpp | 7 +- snes/chip/chip.hpp | 1 - snes/chip/hitachidsp/opcodes.cpp | 13 +- snes/chip/link/link.cpp | 2 +- snes/chip/necdsp/memory.cpp | 12 +- snes/chip/sa1/bus/bus.cpp | 8 +- snes/chip/sa1/memory/memory.cpp | 4 +- snes/chip/sa1/mmio/mmio.cpp | 4 +- snes/chip/serial/serial.cpp | 109 ------- snes/chip/serial/serial.hpp | 28 -- snes/chip/serial/serialization.cpp | 9 - snes/chip/superfx/mmio/mmio.cpp | 4 +- snes/controller/controller.cpp | 55 ++++ snes/controller/controller.hpp | 35 +++ snes/controller/gamepad/gamepad.cpp | 21 ++ snes/controller/gamepad/gamepad.hpp | 9 + snes/controller/justifier/justifier.cpp | 133 ++++++++ snes/controller/justifier/justifier.hpp | 17 ++ snes/controller/mouse/mouse.cpp | 69 +++++ snes/controller/mouse/mouse.hpp | 9 + snes/controller/multitap/multitap.cpp | 39 +++ snes/controller/multitap/multitap.hpp | 10 + snes/controller/serial/serial.cpp | 148 +++++++++ snes/controller/serial/serial.hpp | 19 ++ snes/controller/superscope/superscope.cpp | 129 ++++++++ snes/controller/superscope/superscope.hpp | 22 ++ snes/cpu/cpu.cpp | 10 +- snes/cpu/cpu.hpp | 3 +- snes/cpu/mmio/mmio.cpp | 10 +- snes/cpu/timing/joypad.cpp | 11 +- snes/cpu/timing/timing.cpp | 7 +- snes/input/input.cpp | 356 ++-------------------- snes/input/input.hpp | 109 ++----- snes/interface/interface.hpp | 8 +- snes/libsnes/libsnes.cpp | 6 +- snes/libsnes/libsnes.hpp | 1 + snes/memory/memory-inline.hpp | 1 + snes/snes.hpp | 3 +- snes/system/serialization.cpp | 1 - snes/system/system.cpp | 22 +- snes/video/video.cpp | 26 +- 53 files changed, 1009 insertions(+), 773 deletions(-) delete mode 100644 snes/chip/serial/serial.cpp delete mode 100644 snes/chip/serial/serial.hpp delete mode 100644 snes/chip/serial/serialization.cpp create mode 100644 snes/controller/controller.cpp create mode 100644 snes/controller/controller.hpp create mode 100644 snes/controller/gamepad/gamepad.cpp create mode 100644 snes/controller/gamepad/gamepad.hpp create mode 100644 snes/controller/justifier/justifier.cpp create mode 100644 snes/controller/justifier/justifier.hpp create mode 100644 snes/controller/mouse/mouse.cpp create mode 100644 snes/controller/mouse/mouse.hpp create mode 100644 snes/controller/multitap/multitap.cpp create mode 100644 snes/controller/multitap/multitap.hpp create mode 100644 snes/controller/serial/serial.cpp create mode 100644 snes/controller/serial/serial.hpp create mode 100644 snes/controller/superscope/superscope.cpp create mode 100644 snes/controller/superscope/superscope.hpp diff --git a/.gitignore b/.gitignore index b238204..b8941b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.so *.o *.a +*.dll diff --git a/nall/string/base.hpp b/nall/string/base.hpp index 9972547..fbb820d 100644 --- a/nall/string/base.hpp +++ b/nall/string/base.hpp @@ -25,6 +25,16 @@ namespace nall { inline string& append(unsigned int value); inline string& append(double value); + /* + inline bool equals(const char*) const; + inline bool iequals(const char*) const; + + inline bool wildcard(const char*) const; + inline bool iwildcard(const char*) const; + */ + + inline bool beginswith(const char*) const; + template inline string& operator= (const T& value); template inline string& operator<<(const T& value); diff --git a/nall/string/core.hpp b/nall/string/core.hpp index 16a74af..0db4737 100644 --- a/nall/string/core.hpp +++ b/nall/string/core.hpp @@ -34,6 +34,8 @@ string& string::append(signed int value) { append(integer(value)); return *this; string& string::append(unsigned int value) { append(decimal(value)); return *this; } string& string::append(double value) { append(fp(value)); return *this; } +bool string::beginswith(const char *str) const { return strstr(data, str) == data; } + string::operator const char*() const { return data; } diff --git a/snes/Makefile b/snes/Makefile index cf3b96c..8ce335e 100644 --- a/snes/Makefile +++ b/snes/Makefile @@ -1,12 +1,12 @@ snes_objects := libco -snes_objects += snes-system +snes_objects += snes-system snes-controller 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-nss snes-icd2 snes-superfx snes-sa1 snes-necdsp snes-hitachidsp snes_objects += snes-bsx snes-srtc snes-sdd1 snes-spc7110 snes-sufamiturbo snes_objects += snes-obc1 snes-st0018 -snes_objects += snes-msu1 snes-serial snes-link +snes_objects += snes-msu1 snes-link snes_objects += $(gameboy_objects) objects += $(snes_objects) @@ -34,16 +34,17 @@ obj/libsnes.o: $(snes)/libsnes/libsnes.cpp $(snes)/libsnes/* obj/libco.o : libco/libco.c libco/* -obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/) -obj/snes-memory.o : $(snes)/memory/memory.cpp $(call rwildcard,$(snes)/memory/) -obj/snes-cpucore.o : $(snes)/cpu/core/core.cpp $(call rwildcard,$(snes)/cpu/core/) -obj/snes-smpcore.o : $(snes)/smp/core/core.cpp $(call rwildcard,$(snes)/smp/core/) -obj/snes-cpu.o : $(snescpu)/cpu.cpp $(call rwildcard,$(snescpu)/) -obj/snes-smp.o : $(snessmp)/smp.cpp $(call rwildcard,$(snessmp)/) -obj/snes-dsp.o : $(snesdsp)/dsp.cpp $(call rwildcard,$(snesdsp)/) -obj/snes-ppu.o : $(snesppu)/ppu.cpp $(call rwildcard,$(snesppu)/) -obj/snes-cartridge.o: $(snes)/cartridge/cartridge.cpp $(snes)/cartridge/* -obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(snes)/cheat/* +obj/snes-system.o : $(snes)/system/system.cpp $(call rwildcard,$(snes)/system/) $(call rwildcard,$(snes)/video/) $(call rwildcard,$(snes)/audio/) $(call rwildcard,$(snes)/input/) +obj/snes-controller.o: $(snes)/controller/controller.cpp $(call rwildcard,$(snes)/controller/) +obj/snes-memory.o : $(snes)/memory/memory.cpp $(call rwildcard,$(snes)/memory/) +obj/snes-cpucore.o : $(snes)/cpu/core/core.cpp $(call rwildcard,$(snes)/cpu/core/) +obj/snes-smpcore.o : $(snes)/smp/core/core.cpp $(call rwildcard,$(snes)/smp/core/) +obj/snes-cpu.o : $(snescpu)/cpu.cpp $(call rwildcard,$(snescpu)/) +obj/snes-smp.o : $(snessmp)/smp.cpp $(call rwildcard,$(snessmp)/) +obj/snes-dsp.o : $(snesdsp)/dsp.cpp $(call rwildcard,$(snesdsp)/) +obj/snes-ppu.o : $(snesppu)/ppu.cpp $(call rwildcard,$(snesppu)/) +obj/snes-cartridge.o : $(snes)/cartridge/cartridge.cpp $(snes)/cartridge/* +obj/snes-cheat.o : $(snes)/cheat/cheat.cpp $(snes)/cheat/* obj/snes-nss.o : $(snes)/chip/nss/nss.cpp $(call rwildcard,$(snes)/chip/nss/) obj/snes-icd2.o : $(snes)/chip/icd2/icd2.cpp $(call rwildcard,$(snes)/chip/icd2/) @@ -58,7 +59,6 @@ obj/snes-spc7110.o : $(snes)/chip/spc7110/spc7110.cpp $(snes)/chip/spc7110/* obj/snes-obc1.o : $(snes)/chip/obc1/obc1.cpp $(snes)/chip/obc1/* obj/snes-st0018.o : $(snes)/chip/st0018/st0018.cpp $(snes)/chip/st0018/* obj/snes-msu1.o : $(snes)/chip/msu1/msu1.cpp $(snes)/chip/msu1/* -obj/snes-serial.o : $(snes)/chip/serial/serial.cpp $(snes)/chip/serial/* obj/snes-link.o : $(snes)/chip/link/link.cpp $(snes)/chip/link/* obj/snes-sufamiturbo.o: $(snes)/chip/sufamiturbo/sufamiturbo.cpp $(snes)/chip/sufamiturbo/* diff --git a/snes/alt/cpu/cpu.cpp b/snes/alt/cpu/cpu.cpp index af50eab..97c6209 100644 --- a/snes/alt/cpu/cpu.cpp +++ b/snes/alt/cpu/cpu.cpp @@ -23,6 +23,9 @@ void CPU::step(unsigned clocks) { Processor &chip = *coprocessors[i]; chip.clock -= clocks * (uint64)chip.frequency; } + input.port1->clock -= clocks * (uint64)input.port1->frequency; + input.port2->clock -= clocks * (uint64)input.port2->frequency; + synchronize_controllers(); } void CPU::synchronize_smp() { @@ -41,13 +44,18 @@ void CPU::synchronize_ppu() { } } -void CPU::synchronize_coprocessor() { +void CPU::synchronize_coprocessors() { for(unsigned i = 0; i < coprocessors.size(); i++) { Processor &chip = *coprocessors[i]; if(chip.clock < 0) co_switch(chip.thread); } } +void CPU::synchronize_controllers() { + if(input.port1->clock < 0) co_switch(input.port1->thread); + if(input.port2->clock < 0) co_switch(input.port2->thread); +} + void CPU::Enter() { cpu.enter(); } void CPU::enter() { diff --git a/snes/alt/cpu/cpu.hpp b/snes/alt/cpu/cpu.hpp index 300c353..0394510 100644 --- a/snes/alt/cpu/cpu.hpp +++ b/snes/alt/cpu/cpu.hpp @@ -7,7 +7,8 @@ public: alwaysinline void step(unsigned clocks); alwaysinline void synchronize_smp(); void synchronize_ppu(); - void synchronize_coprocessor(); + void synchronize_coprocessors(); + void synchronize_controllers(); uint8 pio(); bool joylatch(); @@ -41,7 +42,6 @@ private: enum{ DramRefresh, HdmaRun, - ControllerLatch, }; }; nall::priority_queue queue; diff --git a/snes/alt/cpu/mmio.cpp b/snes/alt/cpu/mmio.cpp index 1c23a75..09bd7bc 100644 --- a/snes/alt/cpu/mmio.cpp +++ b/snes/alt/cpu/mmio.cpp @@ -15,13 +15,13 @@ uint8 CPU::mmio_read(unsigned addr) { case 0x4016: { uint8 result = regs.mdr & 0xfc; - result |= input.port_read(0) & 3; + result |= input.port1->data() & 3; return result; } case 0x4017: { uint8 result = (regs.mdr & 0xe0) | 0x1c; - result |= input.port_read(1) & 3; + result |= input.port2->data() & 3; return result; } @@ -127,10 +127,8 @@ void CPU::mmio_write(unsigned addr, uint8 data) { } case 0x4016: { - bool old_latch = status.joypad_strobe_latch; - bool new_latch = data & 1; - status.joypad_strobe_latch = new_latch; - if(old_latch != new_latch) input.poll(); + input.port1->latch(data & 1); + input.port2->latch(data & 1); return; } diff --git a/snes/alt/cpu/timing.cpp b/snes/alt/cpu/timing.cpp index 11083e9..3eea123 100644 --- a/snes/alt/cpu/timing.cpp +++ b/snes/alt/cpu/timing.cpp @@ -4,7 +4,6 @@ void CPU::queue_event(unsigned id) { switch(id) { case QueueEvent::DramRefresh: return add_clocks(40); case QueueEvent::HdmaRun: return hdma_run(); - case QueueEvent::ControllerLatch: return ppu.latch_counters(); } } @@ -62,7 +61,7 @@ void CPU::add_clocks(unsigned clocks) { void CPU::scanline() { synchronize_smp(); synchronize_ppu(); - synchronize_coprocessor(); + synchronize_coprocessors(); system.scanline(); if(vcounter() == 0) hdma_init(); @@ -73,10 +72,6 @@ void CPU::scanline() { queue.enqueue(1104 + 8, QueueEvent::HdmaRun); } - if(vcounter() == input.latchy) { - queue.enqueue(input.latchx, QueueEvent::ControllerLatch); - } - bool nmi_valid = status.nmi_valid; status.nmi_valid = vcounter() >= (ppu.overscan() == false ? 225 : 240); if(!nmi_valid && status.nmi_valid) { @@ -87,16 +82,20 @@ void CPU::scanline() { } if(status.auto_joypad_poll_enabled && vcounter() == (ppu.overscan() == false ? 227 : 242)) { - input.poll(); run_auto_joypad_poll(); } } void CPU::run_auto_joypad_poll() { + input.port1->latch(1); + input.port2->latch(1); + input.port1->latch(0); + input.port2->latch(0); + uint16 joy1 = 0, joy2 = 0, joy3 = 0, joy4 = 0; for(unsigned i = 0; i < 16; i++) { - uint8 port0 = input.port_read(0); - uint8 port1 = input.port_read(1); + uint8 port0 = input.port1->data(); + uint8 port1 = input.port2->data(); joy1 |= (port0 & 1) ? (0x8000 >> i) : 0; joy2 |= (port1 & 1) ? (0x8000 >> i) : 0; diff --git a/snes/cartridge/cartridge.cpp b/snes/cartridge/cartridge.cpp index bc5536d..6be4f72 100644 --- a/snes/cartridge/cartridge.cpp +++ b/snes/cartridge/cartridge.cpp @@ -29,7 +29,6 @@ void Cartridge::load(Mode::e cartridge_mode, const lstring &xml_list) { has_obc1 = false; has_st0018 = false; has_msu1 = false; - has_serial = false; has_link = false; nvram.reset(); diff --git a/snes/cartridge/cartridge.hpp b/snes/cartridge/cartridge.hpp index f9366a0..3359684 100644 --- a/snes/cartridge/cartridge.hpp +++ b/snes/cartridge/cartridge.hpp @@ -49,7 +49,6 @@ public: readonly has_obc1; readonly has_st0018; readonly has_msu1; - readonly has_serial; readonly has_link; struct NonVolatileRAM { @@ -118,9 +117,10 @@ private: void xml_parse_obc1(xml_element&); void xml_parse_setarisc(xml_element&); void xml_parse_msu1(xml_element&); - void xml_parse_serial(xml_element&); void xml_parse_link(xml_element&); + unsigned xml_parse_hex(const string&); + unsigned xml_parse_unsigned(const string&); void xml_parse_address(Mapping&, const string&); void xml_parse_mode(Mapping&, const string&); }; diff --git a/snes/cartridge/xml.cpp b/snes/cartridge/xml.cpp index f33987b..4ad7936 100644 --- a/snes/cartridge/xml.cpp +++ b/snes/cartridge/xml.cpp @@ -1,5 +1,8 @@ #ifdef CARTRIDGE_CPP +#define READ_FUNC uint8 (unsigned) +#define WRITE_FUNC void (unsigned, uint8) + void Cartridge::parse_xml(const lstring &list) { mapping.reset(); parse_xml_cartridge(list[0]); @@ -49,7 +52,6 @@ void Cartridge::parse_xml_cartridge(const char *data) { if(node.name == "obc1") xml_parse_obc1(node); if(node.name == "setarisc") xml_parse_setarisc(node); if(node.name == "msu1") xml_parse_msu1(node); - if(node.name == "serial") xml_parse_serial(node); if(node.name == "link") xml_parse_link(node); } } @@ -73,8 +75,8 @@ void Cartridge::xml_parse_rom(xml_element &root) { foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); } if(m.size == 0) m.size = rom.size(); mapping.append(m); @@ -84,7 +86,7 @@ void Cartridge::xml_parse_rom(xml_element &root) { void Cartridge::xml_parse_ram(xml_element &root) { foreach(attr, root.attribute) { - if(attr.name == "size") ram_size = hex(attr.content); + if(attr.name == "size") ram_size = xml_parse_hex(attr.content); } foreach(leaf, root.element) { @@ -93,8 +95,8 @@ void Cartridge::xml_parse_ram(xml_element &root) { foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); } if(m.size == 0) m.size = ram_size; mapping.append(m); @@ -121,7 +123,7 @@ void Cartridge::xml_parse_nss(xml_element &root) { unsigned value = 0x0000; foreach(attr, leaf.attribute) { if(attr.name == "name") name = attr.parse(); - if(attr.name == "value") value = (uint16)hex(attr.content); + if(attr.name == "value") value = (uint16)xml_parse_hex(attr.content); } information.nss.option[number].append(string( hex<4>(value), ":", name )); } @@ -142,7 +144,7 @@ void Cartridge::xml_parse_icd2(xml_element &root) { foreach(node, root.element) { if(node.name == "map") { - Mapping m(function( &ICD2::read, &icd2 ), function( &ICD2::write, &icd2 )); + Mapping m(function( &ICD2::read, &icd2 ), function( &ICD2::write, &icd2 )); foreach(attr, node.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -162,15 +164,15 @@ void Cartridge::xml_parse_superfx(xml_element &root) { foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); } mapping.append(m); } } } else if(node.name == "ram") { foreach(attr, node.attribute) { - if(attr.name == "size") ram_size = hex(attr.content); + if(attr.name == "size") ram_size = xml_parse_hex(attr.content); } foreach(leaf, node.element) { @@ -179,8 +181,8 @@ void Cartridge::xml_parse_superfx(xml_element &root) { foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); } if(m.size == 0) m.size = ram_size; mapping.append(m); @@ -189,7 +191,7 @@ void Cartridge::xml_parse_superfx(xml_element &root) { } else if(node.name == "mmio") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m( function( &SuperFX::mmio_read, &superfx ), function( &SuperFX::mmio_write, &superfx )); + Mapping m(function( &SuperFX::mmio_read, &superfx ), function( &SuperFX::mmio_write, &superfx )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -209,12 +211,12 @@ void Cartridge::xml_parse_sa1(xml_element &root) { if(subnode.name == "rom") { foreach(leaf, subnode.element) { if(leaf.name == "map") { - Mapping m(function(&SA1::mmc_read, &sa1), function( &SA1::mmc_write, &sa1 )); + Mapping m(function( &SA1::mmc_read, &sa1 ), function( &SA1::mmc_write, &sa1 )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); } mapping.append(m); } @@ -222,7 +224,7 @@ void Cartridge::xml_parse_sa1(xml_element &root) { } else if(subnode.name == "ram") { foreach(leaf, subnode.element) { if(leaf.name == "map") { - Mapping m(function( &SA1::mmc_cpu_read, &sa1 ), function( &SA1::mmc_cpu_write, &sa1 )); + Mapping m(function( &SA1::mmc_cpu_read, &sa1 ), function( &SA1::mmc_cpu_write, &sa1 )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -238,8 +240,8 @@ void Cartridge::xml_parse_sa1(xml_element &root) { foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); } if(m.size == 0) m.size = 2048; mapping.append(m); @@ -247,7 +249,7 @@ void Cartridge::xml_parse_sa1(xml_element &root) { } } else if(node.name == "bwram") { foreach(attr, node.attribute) { - if(attr.name == "size") ram_size = hex(attr.content); + if(attr.name == "size") ram_size = xml_parse_hex(attr.content); } foreach(leaf, node.element) { @@ -256,8 +258,8 @@ void Cartridge::xml_parse_sa1(xml_element &root) { foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); } if(m.size == 0) m.size = ram_size; mapping.append(m); @@ -266,7 +268,7 @@ void Cartridge::xml_parse_sa1(xml_element &root) { } else if(node.name == "mmio") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &SA1::mmio_read, &sa1 ), function( &SA1::mmio_write, &sa1 )); + Mapping m(function( &SA1::mmio_read, &sa1 ), function( &SA1::mmio_write, &sa1 )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -289,11 +291,11 @@ void Cartridge::xml_parse_necdsp(xml_element &root) { string sha256; foreach(attr, root.attribute) { - if(attr.name == "revision") { - if(attr.content == "upd7725" ) necdsp.revision.i = NECDSP::Revision::uPD7725; - if(attr.content == "upd96050") necdsp.revision.i = NECDSP::Revision::uPD96050; + if(attr.name == "model") { + if(attr.content == "uPD7725" ) necdsp.revision.i = NECDSP::Revision::uPD7725; + if(attr.content == "uPD96050") necdsp.revision.i = NECDSP::Revision::uPD96050; } else if(attr.name == "frequency") { - necdsp.frequency = decimal(attr.content); + necdsp.frequency = xml_parse_unsigned(attr.content); } else if(attr.name == "program") { program = attr.content; } else if(attr.name == "sha256") { @@ -331,7 +333,7 @@ void Cartridge::xml_parse_necdsp(xml_element &root) { if(node.name == "dr") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &NECDSP::dr_read, &necdsp ), function( &NECDSP::dr_write, &necdsp )); + Mapping m(function( &NECDSP::dr_read, &necdsp ), function( &NECDSP::dr_write, &necdsp )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -341,7 +343,7 @@ void Cartridge::xml_parse_necdsp(xml_element &root) { } else if(node.name == "sr") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &NECDSP::sr_read, &necdsp ), function( &NECDSP::sr_write, &necdsp )); + Mapping m(function( &NECDSP::sr_read, &necdsp ), function( &NECDSP::sr_write, &necdsp )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -351,7 +353,7 @@ void Cartridge::xml_parse_necdsp(xml_element &root) { } else if(node.name == "dp") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &NECDSP::dp_read, &necdsp ), function( &NECDSP::dp_write, &necdsp )); + Mapping m(function( &NECDSP::dp_read, &necdsp ), function( &NECDSP::dp_write, &necdsp )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -378,24 +380,24 @@ void Cartridge::xml_parse_hitachidsp(xml_element &root) { for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = 0x000000; - string program, sha256; + string dataROM, sha256; foreach(attr, root.attribute) { if(attr.name == "frequency") { - hitachidsp.frequency = decimal(attr.content); - } else if(attr.name == "program") { - program = attr.content; + hitachidsp.frequency = xml_parse_unsigned(attr.content); + } else if(attr.name == "data") { + dataROM = attr.content; } else if(attr.name == "sha256") { sha256 = attr.content; } } - string path = string( dir(system.interface->path(Slot::Base, ".dsp")), program ); + string path(dir(system.interface->path(Slot::Base, ".dsp")), dataROM); file fp; if(fp.open(path, file::mode_read) == false) { - system.interface->message(string( "Warning: Hitachi DSP program ", program, " is missing." )); + system.interface->message(string( "Warning: Hitachi DSP data ", dataROM, " is missing." )); } else if(fp.size() != 1024 * 3) { - system.interface->message(string( "Warning: Hitachi DSP program ", program, " is of the wrong file size." )); + system.interface->message(string( "Warning: Hitachi DSP data ", dataROM, " is of the wrong file size." )); fp.close(); } else { for(unsigned n = 0; n < 1024; n++) hitachidsp.dataROM[n] = fp.readl(3); @@ -417,7 +419,7 @@ void Cartridge::xml_parse_hitachidsp(xml_element &root) { foreach(n, hash) filehash.append(hex<2>(n)); if(sha256 != filehash) { - system.interface->message(string( "Warning: Hitachi DSP program ", program, " SHA256 sum is incorrect." )); + system.interface->message(string( "Warning: Hitachi DSP data ", dataROM, " SHA256 sum is incorrect." )); } } @@ -425,25 +427,29 @@ void Cartridge::xml_parse_hitachidsp(xml_element &root) { } foreach(node, root.element) { - if(node.name == "rom") foreach(leaf, node.element) { - if(leaf.name == "map") { - Mapping m(function( &HitachiDSP::rom_read, &hitachidsp ), function( &HitachiDSP::rom_write, &hitachidsp )); + if(node.name == "rom") { + foreach(leaf, node.element) { + if(leaf.name == "map") { + Mapping m(function( &HitachiDSP::rom_read, &hitachidsp ), function( &HitachiDSP::rom_write, &hitachidsp )); + foreach(attr, leaf.attribute) { + if(attr.name == "address") xml_parse_address(m, attr.content); + if(attr.name == "mode") xml_parse_mode(m, attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); + } + mapping.append(m); + } + } + } + if(node.name == "mmio") { + foreach(leaf, node.element) { + Mapping m(function( &HitachiDSP::dsp_read, &hitachidsp ), function( &HitachiDSP::dsp_write, &hitachidsp )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); - if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); } mapping.append(m); } } - if(node.name == "mmio") foreach(leaf, node.element) { - Mapping m(function( &HitachiDSP::dsp_read, &hitachidsp ), function( &HitachiDSP::dsp_write, &hitachidsp )); - foreach(attr, leaf.attribute) { - if(attr.name == "address") xml_parse_address(m, attr.content); - } - mapping.append(m); - } } } @@ -458,8 +464,8 @@ void Cartridge::xml_parse_bsx(xml_element &root) { foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); } mapping.append(m); } @@ -467,7 +473,7 @@ void Cartridge::xml_parse_bsx(xml_element &root) { } else if(node.name == "mcu") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &BSXCartridge::mcu_read, &bsxcartridge ), function( &BSXCartridge::mcu_write, &bsxcartridge )); + Mapping m(function( &BSXCartridge::mcu_read, &bsxcartridge ), function( &BSXCartridge::mcu_write, &bsxcartridge )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -477,7 +483,7 @@ void Cartridge::xml_parse_bsx(xml_element &root) { } else if(node.name == "mmio") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &BSXCartridge::mmio_read, &bsxcartridge ), function( &BSXCartridge::mmio_write, &bsxcartridge )); + Mapping m(function( &BSXCartridge::mmio_read, &bsxcartridge ), function( &BSXCartridge::mmio_write, &bsxcartridge )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -510,8 +516,8 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) { foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); } if(m.size == 0) m.size = memory.size(); if(m.size) mapping.append(m); @@ -521,7 +527,7 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) { unsigned ram_size = 0; foreach(attr, slot.attribute) { - if(attr.name == "size") ram_size = hex(attr.content); + if(attr.name == "size") ram_size = xml_parse_hex(attr.content); } foreach(leaf, slot.element) { @@ -531,8 +537,8 @@ void Cartridge::xml_parse_sufamiturbo(xml_element &root) { foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); } if(m.size == 0) m.size = ram_size; if(m.size) mapping.append(m); @@ -549,7 +555,7 @@ void Cartridge::xml_parse_srtc(xml_element &root) { foreach(node, root.element) { if(node.name == "map") { - Mapping m(function( &SRTC::read, &srtc ), function( &SRTC::write, &srtc )); + Mapping m(function( &SRTC::read, &srtc ), function( &SRTC::write, &srtc )); foreach(attr, node.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -565,7 +571,7 @@ void Cartridge::xml_parse_sdd1(xml_element &root) { if(node.name == "mcu") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &SDD1::mcu_read, &sdd1 ), function( &SDD1::mcu_write, &sdd1 )); + Mapping m(function( &SDD1::mcu_read, &sdd1 ), function( &SDD1::mcu_write, &sdd1 )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -575,7 +581,7 @@ void Cartridge::xml_parse_sdd1(xml_element &root) { } else if(node.name == "mmio") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &SDD1::mmio_read, &sdd1 ), function( &SDD1::mmio_write, &sdd1 )); + Mapping m(function( &SDD1::mmio_read, &sdd1 ), function( &SDD1::mmio_write, &sdd1 )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -594,7 +600,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) { if(node.name == "dcu") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &SPC7110::dcu_read, &spc7110 ), function( &SPC7110::dcu_write, &spc7110 )); + Mapping m(function( &SPC7110::dcu_read, &spc7110 ), function( &SPC7110::dcu_write, &spc7110 )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -604,10 +610,10 @@ void Cartridge::xml_parse_spc7110(xml_element &root) { } else if(node.name == "mcu") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &SPC7110::mcu_read, &spc7110 ), function( &SPC7110::mcu_write, &spc7110 )); + Mapping m(function( &SPC7110::mcu_read, &spc7110 ), function( &SPC7110::mcu_write, &spc7110 )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); - if(attr.name == "offset") spc7110.data_rom_offset = hex(attr.content); + if(attr.name == "offset") spc7110.data_rom_offset = xml_parse_hex(attr.content); } mapping.append(m); } @@ -615,7 +621,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) { } else if(node.name == "mmio") { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &SPC7110::mmio_read, &spc7110 ), function( &SPC7110::mmio_write, &spc7110 )); + Mapping m(function( &SPC7110::mmio_read, &spc7110 ), function( &SPC7110::mmio_write, &spc7110 )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -624,17 +630,17 @@ void Cartridge::xml_parse_spc7110(xml_element &root) { } } else if(node.name == "ram") { foreach(attr, node.attribute) { - if(attr.name == "size") ram_size = hex(attr.content); + if(attr.name == "size") ram_size = xml_parse_hex(attr.content); } foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &SPC7110::ram_read, &spc7110 ), function( &SPC7110::ram_write, &spc7110 )); + Mapping m(function( &SPC7110::ram_read, &spc7110 ), function( &SPC7110::ram_write, &spc7110 )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); if(attr.name == "mode") xml_parse_mode(m, attr.content); - if(attr.name == "offset") m.offset = hex(attr.content); - if(attr.name == "size") m.size = hex(attr.content); + if(attr.name == "offset") m.offset = xml_parse_hex(attr.content); + if(attr.name == "size") m.size = xml_parse_hex(attr.content); } mapping.append(m); } @@ -644,7 +650,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) { foreach(leaf, node.element) { if(leaf.name == "map") { - Mapping m(function( &SPC7110::mmio_read, &spc7110 ), function( &SPC7110::mmio_write, &spc7110 )); + Mapping m(function( &SPC7110::mmio_read, &spc7110 ), function( &SPC7110::mmio_write, &spc7110 )); foreach(attr, leaf.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -660,7 +666,7 @@ void Cartridge::xml_parse_obc1(xml_element &root) { foreach(node, root.element) { if(node.name == "map") { - Mapping m(function( &OBC1::read, &obc1 ), function( &OBC1::write, &obc1 )); + Mapping m(function( &OBC1::read, &obc1 ), function( &OBC1::write, &obc1 )); foreach(attr, node.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -674,7 +680,7 @@ void Cartridge::xml_parse_setarisc(xml_element &root) { foreach(node, root.element) { if(node.name == "map") { - Mapping m(function( &ST0018::mmio_read, &st0018 ), function( &ST0018::mmio_write, &st0018 )); + Mapping m(function( &ST0018::mmio_read, &st0018 ), function( &ST0018::mmio_write, &st0018 )); foreach(attr, node.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -688,7 +694,7 @@ void Cartridge::xml_parse_msu1(xml_element &root) { foreach(node, root.element) { if(node.name == "map") { - Mapping m(function( &MSU1::mmio_read, &msu1 ), function( &MSU1::mmio_write, &msu1 )); + Mapping m(function( &MSU1::mmio_read, &msu1 ), function( &MSU1::mmio_write, &msu1 )); foreach(attr, node.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -697,23 +703,19 @@ void Cartridge::xml_parse_msu1(xml_element &root) { } } -void Cartridge::xml_parse_serial(xml_element &root) { - has_serial = true; -} - void Cartridge::xml_parse_link(xml_element &root) { has_link = true; link.frequency = 1; link.program = ""; foreach(attr, root.attribute) { - if(attr.name == "frequency") link.frequency = decimal(attr.content); + if(attr.name == "frequency") link.frequency = xml_parse_unsigned(attr.content); if(attr.name == "program") link.program = attr.content; } foreach(node, root.element) { if(node.name == "map") { - Mapping m(function(&Link::read, &link), function(&Link::write, &link)); + Mapping m(function( &Link::read, &link ), function( &Link::write, &link )); foreach(attr, node.attribute) { if(attr.name == "address") xml_parse_address(m, attr.content); } @@ -722,6 +724,15 @@ void Cartridge::xml_parse_link(xml_element &root) { } } +unsigned Cartridge::xml_parse_hex(const string &s) { + return hex(s); +} + +unsigned Cartridge::xml_parse_unsigned(const string &s) { + if(s.beginswith("0x")) return hex(s); + return integer(s); +} + void Cartridge::xml_parse_address(Mapping &m, const string &data) { lstring part; part.split(":", data); @@ -759,13 +770,13 @@ Cartridge::Mapping::Mapping() { } Cartridge::Mapping::Mapping(Memory &memory) { - read = function( &Memory::read, &memory ); - write = function( &Memory::write, &memory ); + read = function( &Memory::read, &memory ); + write = function( &Memory::write, &memory ); mode.i = Bus::MapMode::Direct; banklo = bankhi = addrlo = addrhi = offset = size = 0; } -Cartridge::Mapping::Mapping(const function &read_, const function &write_) { +Cartridge::Mapping::Mapping(const function &read_, const function &write_) { read = read_; write = write_; mode.i = Bus::MapMode::Direct; diff --git a/snes/cheat/cheat.cpp b/snes/cheat/cheat.cpp index d58d229..fd5b093 100644 --- a/snes/cheat/cheat.cpp +++ b/snes/cheat/cheat.cpp @@ -15,7 +15,7 @@ void Cheat::enable(bool state) { } void Cheat::synchronize() { - memcpy(bus.lookup, lookup, 16 * 1024 * 1024); + memset(override, 0x00, 16 * 1024 * 1024); code_enabled = false; for(unsigned i = 0; i < size(); i++) { @@ -26,16 +26,16 @@ void Cheat::synchronize() { code_enabled = true; unsigned addr = mirror(code.addr[n]); - bus.lookup[addr] = 0xff; + override[addr] = true; if((addr & 0xffe000) == 0x7e0000) { //mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff unsigned mirroraddr; for(unsigned x = 0; x <= 0x3f; x++) { mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff); - bus.lookup[mirroraddr] = 0xff; + override[mirroraddr] = true; mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff); - bus.lookup[mirroraddr] = 0xff; + override[mirroraddr] = true; } } } @@ -61,29 +61,17 @@ uint8 Cheat::read(unsigned addr) const { return 0x00; } -uint8 Cheat::default_reader(unsigned addr) { - bus.reader[cheat.lookup[addr]](bus.target[addr]); - return cheat.read(addr); -} - -void Cheat::default_writer(unsigned addr, uint8 data) { - return bus.writer[cheat.lookup[addr]](bus.target[addr], data); -} - void Cheat::init() { - bus.reader[0xff] = function(&Cheat::default_reader); - bus.writer[0xff] = function(&Cheat::default_writer); - - memcpy(lookup, bus.lookup, 16 * 1024 * 1024); + memset(override, 0x00, 16 * 1024 * 1024); } Cheat::Cheat() { - lookup = new uint8[16 * 1024 * 1024]; + override = new uint8[16 * 1024 * 1024]; system_enabled = true; } Cheat::~Cheat() { - delete[] lookup; + delete[] override; } //=============== diff --git a/snes/cheat/cheat.hpp b/snes/cheat/cheat.hpp index ca937ee..d39213c 100644 --- a/snes/cheat/cheat.hpp +++ b/snes/cheat/cheat.hpp @@ -9,7 +9,8 @@ struct CheatCode { class Cheat : public linear_vector { public: - struct Type{ enum e{ ProActionReplay, GameGenie } i; }; + struct Type { enum e { ProActionReplay, GameGenie } i; }; + uint8 *override; bool enabled() const; void enable(bool); @@ -24,14 +25,10 @@ public: static bool encode(string&, unsigned, uint8, Type); private: - uint8 *lookup; bool system_enabled; bool code_enabled; bool cheat_enabled; unsigned mirror(unsigned) const; - - static uint8 default_reader(unsigned); - static void default_writer(unsigned, uint8); }; extern Cheat cheat; diff --git a/snes/chip/chip.hpp b/snes/chip/chip.hpp index cad811d..09f5162 100644 --- a/snes/chip/chip.hpp +++ b/snes/chip/chip.hpp @@ -17,7 +17,6 @@ struct Coprocessor : Processor { #include #include #include -#include #include void Coprocessor::step(unsigned clocks) { diff --git a/snes/chip/hitachidsp/opcodes.cpp b/snes/chip/hitachidsp/opcodes.cpp index 8d2158b..f207274 100755 --- a/snes/chip/hitachidsp/opcodes.cpp +++ b/snes/chip/hitachidsp/opcodes.cpp @@ -78,7 +78,7 @@ void HitachiDSP::exec() { else if((opcode & 0xdd00) == 0x1400) { //00.1 01.0 .... .... - //jumpmi + //jumpmi i if(regs.n) { if(opcode & 0x2000) push(); regs.pc = np(); @@ -87,7 +87,7 @@ void HitachiDSP::exec() { else if((opcode & 0xffff) == 0x1c00) { //0001 1100 0000 0000 - //loop/wait? + //loop? } else if((opcode & 0xfffe) == 0x2500) { @@ -110,6 +110,7 @@ void HitachiDSP::exec() { else if((opcode & 0xffff) == 0x3c00) { //0011 1100 0000 0000 + //ret pull(); } @@ -121,7 +122,7 @@ void HitachiDSP::exec() { else if((opcode & 0xf800) == 0x4800) { //0100 1... .... .... - //rcmp a<> 8; } void NECDSP::sr_write(unsigned, uint8 data) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); } uint8 NECDSP::dr_read(unsigned) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); if(regs.sr.drc == 0) { //16-bit if(regs.sr.drs == 0) { @@ -29,7 +29,7 @@ uint8 NECDSP::dr_read(unsigned) { } void NECDSP::dr_write(unsigned, uint8 data) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); if(regs.sr.drc == 0) { //16-bit if(regs.sr.drs == 0) { @@ -48,7 +48,7 @@ void NECDSP::dr_write(unsigned, uint8 data) { } uint8 NECDSP::dp_read(unsigned addr) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); bool hi = addr & 1; addr = (addr >> 1) & 2047; @@ -60,7 +60,7 @@ uint8 NECDSP::dp_read(unsigned addr) { } void NECDSP::dp_write(unsigned addr, uint8 data) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); bool hi = addr & 1; addr = (addr >> 1) & 2047; diff --git a/snes/chip/sa1/bus/bus.cpp b/snes/chip/sa1/bus/bus.cpp index 3dd02e9..a632551 100644 --- a/snes/chip/sa1/bus/bus.cpp +++ b/snes/chip/sa1/bus/bus.cpp @@ -7,12 +7,12 @@ unsigned SA1::CPUIRAM::size() const { } uint8 SA1::CPUIRAM::read(unsigned addr) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); return sa1.iram.read(addr); } void SA1::CPUIRAM::write(unsigned addr, uint8 data) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); sa1.iram.write(addr, data); } @@ -21,13 +21,13 @@ unsigned SA1::CPUBWRAM::size() const { } uint8 SA1::CPUBWRAM::read(unsigned addr) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); if(dma) return sa1.dma_cc1_read(addr); return cartridge.ram.read(addr); } void SA1::CPUBWRAM::write(unsigned addr, uint8 data) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); cartridge.ram.write(addr, data); } diff --git a/snes/chip/sa1/memory/memory.cpp b/snes/chip/sa1/memory/memory.cpp index 7210bf6..1d66e7a 100644 --- a/snes/chip/sa1/memory/memory.cpp +++ b/snes/chip/sa1/memory/memory.cpp @@ -182,13 +182,13 @@ void SA1::mmc_write(unsigned addr, uint8 data) { } uint8 SA1::mmc_cpu_read(unsigned addr) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size()); return cpubwram.read(addr); } void SA1::mmc_cpu_write(unsigned addr, uint8 data) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); addr = bus.mirror(mmio.sbm * 0x2000 + (addr & 0x1fff), cpubwram.size()); cpubwram.write(addr, data); } diff --git a/snes/chip/sa1/mmio/mmio.cpp b/snes/chip/sa1/mmio/mmio.cpp index ac4e28f..c4a894b 100644 --- a/snes/chip/sa1/mmio/mmio.cpp +++ b/snes/chip/sa1/mmio/mmio.cpp @@ -444,7 +444,7 @@ uint8 SA1::mmio_r230e() { } uint8 SA1::mmio_read(unsigned addr) { - (co_active() == cpu.thread ? cpu.synchronize_coprocessor() : synchronize_cpu()); + (co_active() == cpu.thread ? cpu.synchronize_coprocessors() : synchronize_cpu()); addr &= 0xffff; switch(addr) { @@ -469,7 +469,7 @@ uint8 SA1::mmio_read(unsigned addr) { } void SA1::mmio_write(unsigned addr, uint8 data) { - (co_active() == cpu.thread ? cpu.synchronize_coprocessor() : synchronize_cpu()); + (co_active() == cpu.thread ? cpu.synchronize_coprocessors() : synchronize_cpu()); addr &= 0xffff; switch(addr) { diff --git a/snes/chip/serial/serial.cpp b/snes/chip/serial/serial.cpp deleted file mode 100644 index a7021d0..0000000 --- a/snes/chip/serial/serial.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include - -#define SERIAL_CPP -namespace SNES { - -Serial serial; - -#include "serialization.cpp" - -static void snesserial_tick(unsigned clocks) { serial.add_clocks(clocks * 8); } -static uint8 snesserial_read() { return serial.read(); } -static void snesserial_write(uint8 data) { serial.write(data); } - -void Serial::Enter() { serial.enter(); } - -void Serial::enter() { - data1 = 0; - data2 = 0; - add_clocks(256 * 8); //warm-up - if(flowcontrol()) data2 = 1; - if(main) main(snesserial_tick, snesserial_read, snesserial_write); - while(true) add_clocks(frequency); //snesserial_main() fallback -} - -void Serial::add_clocks(unsigned clocks) { - step(clocks); - synchronize_cpu(); -} - -uint8 Serial::read() { - while(cpu.joylatch() == 0) add_clocks(1); - while(cpu.joylatch() == 1) add_clocks(1); - add_clocks(4); - - uint8 data = 0; - for(unsigned i = 0; i < 8; i++) { - add_clocks(8); - data = (cpu.joylatch() << 7) | (data >> 1); - } - - return data; -} - -void Serial::write(uint8 data) { - if(flowcontrol()) while(cpu.pio() & 0x80) add_clocks(1); - add_clocks(8); - - data1 = 1; - add_clocks(8); - - for(unsigned i = 0; i < 8; i++) { - data1 = (data & 1) ^ 1; - data >>= 1; - add_clocks(8); - } - - data1 = 0; - add_clocks(8); -} - -uint8 Serial::mmio_read(unsigned addr) { - cpu.synchronize_coprocessor(); - switch(addr & 1) { default: - case 0: return cpu.mmio_read(addr); - case 1: return cpu.mmio_read(addr); - } -} - -void Serial::mmio_write(unsigned addr, uint8 data) { - cpu.synchronize_coprocessor(); - switch(addr & 1) { default: - case 0: cpu.mmio_write(addr, data); break; - case 1: cpu.mmio_write(addr, data); break; - } -} - -void Serial::init() { -} - -void Serial::load() { - if(opened()) close(); - string basename = system.interface->path(Cartridge::Slot::Base, ""); - string name = notdir(basename); - string path = dir(basename); - if(open(name, path)) { - baudrate = sym("snesserial_baudrate"); - flowcontrol = sym("snesserial_flowcontrol"); - main = sym("snesserial_main"); - } - - function reader(&Serial::mmio_read, &serial); - function writer(&Serial::mmio_write, &serial); - bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, reader, writer); - bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, reader, writer); -} - -void Serial::unload() { - if(opened()) close(); -} - -void Serial::power() { - reset(); -} - -void Serial::reset() { - create(Serial::Enter, baudrate() * 8); -} - -} diff --git a/snes/chip/serial/serial.hpp b/snes/chip/serial/serial.hpp deleted file mode 100644 index 361f79c..0000000 --- a/snes/chip/serial/serial.hpp +++ /dev/null @@ -1,28 +0,0 @@ -class Serial : public Coprocessor, public library, public property { -public: - static void Enter(); - void enter(); - void init(); - void load(); - void unload(); - void power(); - void reset(); - void serialize(serializer&); - - readonly data1; - readonly data2; - - void add_clocks(unsigned clocks); - uint8 read(); - void write(uint8 data); - - uint8 mmio_read(unsigned addr); - void mmio_write(unsigned addr, uint8 data); - -private: - function baudrate; - function flowcontrol; - function main; -}; - -extern Serial serial; diff --git a/snes/chip/serial/serialization.cpp b/snes/chip/serial/serialization.cpp deleted file mode 100644 index 6a897c7..0000000 --- a/snes/chip/serial/serialization.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#ifdef SERIAL_CPP - -void Serial::serialize(serializer &s) { - Processor::serialize(s); - s.integer((bool&)data1); - s.integer((bool&)data2); -} - -#endif diff --git a/snes/chip/superfx/mmio/mmio.cpp b/snes/chip/superfx/mmio/mmio.cpp index 7bf43b1..5650a77 100644 --- a/snes/chip/superfx/mmio/mmio.cpp +++ b/snes/chip/superfx/mmio/mmio.cpp @@ -1,7 +1,7 @@ #ifdef SUPERFX_CPP uint8 SuperFX::mmio_read(unsigned addr) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); addr &= 0xffff; if(addr >= 0x3100 && addr <= 0x32ff) { @@ -53,7 +53,7 @@ uint8 SuperFX::mmio_read(unsigned addr) { } void SuperFX::mmio_write(unsigned addr, uint8 data) { - cpu.synchronize_coprocessor(); + cpu.synchronize_coprocessors(); addr &= 0xffff; if(addr >= 0x3100 && addr <= 0x32ff) { diff --git a/snes/controller/controller.cpp b/snes/controller/controller.cpp new file mode 100644 index 0000000..539e8c7 --- /dev/null +++ b/snes/controller/controller.cpp @@ -0,0 +1,55 @@ +#include + +#define CONTROLLER_CPP +namespace SNES { + +#include "gamepad/gamepad.cpp" +#include "multitap/multitap.cpp" +#include "mouse/mouse.cpp" +#include "superscope/superscope.cpp" +#include "justifier/justifier.cpp" +#include "serial/serial.cpp" + +void Controller::Enter() { + if(co_active() == input.port1->thread) input.port1->enter(); + if(co_active() == input.port2->thread) input.port2->enter(); +} + +void Controller::enter() { + while(true) step(1); +} + +void Controller::step(unsigned clocks) { + clock += clocks * (uint64)cpu.frequency; + synchronize_cpu(); +} + +void Controller::synchronize_cpu() { + if(CPU::Threaded == true) { + if(clock >= 0 && scheduler.sync.i != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); + } else { + while(clock >= 0) cpu.enter(); + } +} + +bool Controller::iobit() { + switch(port ? 1 : 0) { + case Controller::Port1: return cpu.pio() & 0x40; + case Controller::Port2: return cpu.pio() & 0x80; + } + + return false; +} + +void Controller::iobit(bool data) { + switch(port ? 1 : 0) { + case Controller::Port1: bus.write(0x4201, (cpu.pio() & ~0x40) | (data << 6)); break; + case Controller::Port2: bus.write(0x4201, (cpu.pio() & ~0x80) | (data << 7)); break; + } +} + +Controller::Controller(bool port) : port(port) { + if(!thread) create(Controller::Enter, 1); +} + +} diff --git a/snes/controller/controller.hpp b/snes/controller/controller.hpp new file mode 100644 index 0000000..b232724 --- /dev/null +++ b/snes/controller/controller.hpp @@ -0,0 +1,35 @@ +// SNES controller port pinout: +// ------------------------------- +// | (1) (2) (3) (4) | (5) (6) (7) ) +// ------------------------------- +// pin name port1 port2 +// 1: +5v +// 2: clock $4016 read $4017 read +// 3: latch $4016.d0 write $4016.d0 write +// 4: data1 $4016.d0 read $4017.d0 read +// 5: data2 $4016.d1 read $4017.d1 read +// 6: iobit $4201.d6 write; $4213.d6 read $4201.d7 write; $4213.d7 read +// 7: gnd + +struct Controller : Processor { + enum { Port1 = 0, Port2 = 1 }; + const bool port; + + static void Enter(); + virtual void enter(); + void step(unsigned clocks); + void synchronize_cpu(); + + bool iobit(); + void iobit(bool data); + virtual uint2 data() { return 0; } + virtual void latch(bool data) {} + Controller(bool port); +}; + +#include "gamepad/gamepad.hpp" +#include "multitap/multitap.hpp" +#include "mouse/mouse.hpp" +#include "superscope/superscope.hpp" +#include "justifier/justifier.hpp" +#include "serial/serial.hpp" diff --git a/snes/controller/gamepad/gamepad.cpp b/snes/controller/gamepad/gamepad.cpp new file mode 100644 index 0000000..d083023 --- /dev/null +++ b/snes/controller/gamepad/gamepad.cpp @@ -0,0 +1,21 @@ +#ifdef CONTROLLER_CPP + +uint2 Gamepad::data() { + if(counter >= 16) return 1; + uint2 result = system.interface->input_poll(port, Input::Device::Joypad, 0, counter); + if(latched == 0) counter++; + return result; +} + +void Gamepad::latch(bool data) { + if(latched == data) return; + latched = data; + counter = 0; +} + +Gamepad::Gamepad(bool port) : Controller(port) { + latched = 0; + counter = 0; +} + +#endif diff --git a/snes/controller/gamepad/gamepad.hpp b/snes/controller/gamepad/gamepad.hpp new file mode 100644 index 0000000..c5ca69c --- /dev/null +++ b/snes/controller/gamepad/gamepad.hpp @@ -0,0 +1,9 @@ +struct Gamepad : Controller { + uint2 data(); + void latch(bool data); + Gamepad(bool port); + +private: + bool latched; + unsigned counter; +}; diff --git a/snes/controller/justifier/justifier.cpp b/snes/controller/justifier/justifier.cpp new file mode 100644 index 0000000..b583cc0 --- /dev/null +++ b/snes/controller/justifier/justifier.cpp @@ -0,0 +1,133 @@ +#ifdef CONTROLLER_CPP + +void Justifier::enter() { + unsigned prev = 0; + while(true) { + unsigned next = cpu.vcounter() * 1364 + cpu.hcounter(); + + signed x = (active == 0 ? x1 : x2), y = (active == 0 ? y1 : y2); + bool offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225)); + + if(offscreen == false) { + unsigned target = y * 1364 + (x + 24) * 4; + if(next >= target && prev < target) { + //CRT raster detected, toggle iobit to latch counters + iobit(0); + iobit(1); + } + } + + if(next < prev) { + int nx1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::X); + int ny1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Y); + nx1 += x1; + ny1 += y1; + x1 = max(-16, min(256 + 16, nx1)); + y1 = max(-16, min(240 + 16, ny1)); + + if(chained == true) { + int nx2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::X); + int ny2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Y); + nx2 += x2; + ny2 += y2; + x2 = max(-16, min(256 + 16, nx2)); + y2 = max(-16, min(240 + 16, ny2)); + } + } else { + //sleep until PPU counters are close to latch position + unsigned diff = abs((signed)y - cpu.vcounter()); + if(diff >= 2) step((diff - 2) * 1364); + } + + prev = next; + step(2); + } +} + +uint2 Justifier::data() { + if(counter >= 32) return 1; + + if(counter == 0) { + trigger1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Trigger); + start1 = system.interface->input_poll(port, Input::Device::Justifier, 0, (unsigned)Input::JustifierID::Start); + if(chained) { + trigger2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Trigger); + start2 = system.interface->input_poll(port, Input::Device::Justifiers, 1, (unsigned)Input::JustifierID::Start); + } + } + + switch(counter++) { + case 0: return 0; + case 1: return 0; + case 2: return 0; + case 3: return 0; + case 4: return 0; + case 5: return 0; + case 6: return 0; + case 7: return 0; + case 8: return 0; + case 9: return 0; + case 10: return 0; + case 11: return 0; + + case 12: return 1; //signature + case 13: return 1; // || + case 14: return 1; // || + case 15: return 0; // || + + case 16: return 0; + case 17: return 1; + case 18: return 0; + case 19: return 1; + case 20: return 0; + case 21: return 1; + case 22: return 0; + case 23: return 1; + + case 24: return trigger1; + case 25: return trigger2; + case 26: return start1; + case 27: return start2; + case 28: return active; + + case 29: return 0; + case 30: return 0; + case 31: return 0; + } + + return 0; +} + +void Justifier::latch(bool data) { + if(latched == data) return; + latched = data; + counter = 0; + if(latched == 0) active = !active; //toggle between both controllers, even when unchained +} + +Justifier::Justifier(bool port, bool chained) : Controller(port), chained(chained) { + create(Controller::Enter, 21477272); + latched = 0; + counter = 0; + active = 0; + + if(chained == false) { + x1 = 256 / 2; + y1 = 240 / 2; + x2 = -1; + y2 = -1; + } else { + x1 = 256 / 2 - 16; + y1 = 240 / 2; + x2 = 256 / 2 + 16; + y2 = 240 / 2; + } + + trigger1 = false; + trigger2 = false; + + start1 = false; + start2 = false; +} + +#endif diff --git a/snes/controller/justifier/justifier.hpp b/snes/controller/justifier/justifier.hpp new file mode 100644 index 0000000..8259147 --- /dev/null +++ b/snes/controller/justifier/justifier.hpp @@ -0,0 +1,17 @@ +struct Justifier : Controller { + void enter(); + uint2 data(); + void latch(bool data); + Justifier(bool port, bool chained); + +//private: + const bool chained; //true if the second justifier is attached to the first + bool latched; + unsigned counter; + + bool active; + signed x1, x2; + signed y1, y2; + bool trigger1, trigger2; + bool start1, start2; +}; diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp new file mode 100644 index 0000000..0b05e5d --- /dev/null +++ b/snes/controller/mouse/mouse.cpp @@ -0,0 +1,69 @@ +#ifdef CONTROLLER_CPP + +uint2 Mouse::data() { + if(counter >= 32) return 1; + + int position_x = system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right + int position_y = system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down + + bool direction_x = position_x < 0; //0 = right, 1 = left + bool direction_y = position_y < 0; //0 = down, 1 = up + + if(position_x < 0) position_x = -position_x; //abs(position_x) + if(position_y < 0) position_y = -position_y; //abs(position_y) + + position_x = min(127, position_x); //range = 0 - 127 + position_y = min(127, position_y); + + switch(counter++) { default: + case 0: return 0; + case 1: return 0; + case 2: return 0; + case 3: return 0; + case 4: return 0; + case 5: return 0; + case 6: return 0; + case 7: return 0; + + case 8: return system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Right); + case 9: return system.interface->input_poll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Left); + case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused) + case 11: return 0; // || + + case 12: return 0; //signature + case 13: return 0; // || + case 14: return 0; // || + case 15: return 1; // || + + case 16: return (direction_y); + case 17: return (position_y >> 6) & 1; + case 18: return (position_y >> 5) & 1; + case 19: return (position_y >> 4) & 1; + case 20: return (position_y >> 3) & 1; + case 21: return (position_y >> 2) & 1; + case 22: return (position_y >> 1) & 1; + case 23: return (position_y >> 0) & 1; + + case 24: return (direction_x); + case 25: return (position_x >> 6) & 1; + case 26: return (position_x >> 5) & 1; + case 27: return (position_x >> 4) & 1; + case 28: return (position_x >> 3) & 1; + case 29: return (position_x >> 2) & 1; + case 30: return (position_x >> 1) & 1; + case 31: return (position_x >> 0) & 1; + } +} + +void Mouse::latch(bool data) { + if(latched == data) return; + latched = data; + counter = 0; +} + +Mouse::Mouse(bool port) : Controller(port) { + latched = 0; + counter = 0; +} + +#endif diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp new file mode 100644 index 0000000..95e24b6 --- /dev/null +++ b/snes/controller/mouse/mouse.hpp @@ -0,0 +1,9 @@ +struct Mouse : Controller { + uint2 data(); + void latch(bool data); + Mouse(bool port); + +private: + bool latched; + unsigned counter; +}; diff --git a/snes/controller/multitap/multitap.cpp b/snes/controller/multitap/multitap.cpp new file mode 100644 index 0000000..df04054 --- /dev/null +++ b/snes/controller/multitap/multitap.cpp @@ -0,0 +1,39 @@ +#ifdef CONTROLLER_CPP + +uint2 Multitap::data() { + if(latched) return 2; //multitap detection + unsigned index, port1, port2; + + if(iobit()) { + index = counter1; + if(index >= 16) return 3; + counter1++; + port1 = 0; //controller 1 + port2 = 1; //controller 2 + } else { + index = counter2; + if(index >= 16) return 3; + counter2++; + port1 = 2; //controller 3 + port2 = 3; //controller 4 + } + + bool data1 = system.interface->input_poll(port, Input::Device::Multitap, port1, index); + bool data2 = system.interface->input_poll(port, Input::Device::Multitap, port2, index); + return (data2 << 1) | (data1 << 0); +} + +void Multitap::latch(bool data) { + if(latched == data) return; + latched = data; + counter1 = 0; + counter2 = 0; +} + +Multitap::Multitap(bool port) : Controller(port) { + latched = 0; + counter1 = 0; + counter2 = 0; +} + +#endif diff --git a/snes/controller/multitap/multitap.hpp b/snes/controller/multitap/multitap.hpp new file mode 100644 index 0000000..0540af7 --- /dev/null +++ b/snes/controller/multitap/multitap.hpp @@ -0,0 +1,10 @@ +struct Multitap : Controller { + uint2 data(); + void latch(bool data); + Multitap(bool port); + +private: + bool latched; + unsigned counter1; + unsigned counter2; +}; diff --git a/snes/controller/serial/serial.cpp b/snes/controller/serial/serial.cpp new file mode 100644 index 0000000..107bea1 --- /dev/null +++ b/snes/controller/serial/serial.cpp @@ -0,0 +1,148 @@ +#ifdef CONTROLLER_CPP + +//Serial communications cable emulation: +//The SNES controller ports can be used for bi-directional serial communication +//when wired to a specialized controller. This class implements said controller, +//for the primary purpose of testing code outside of real hardware. + +//The basic idea is to wire the SNES controller pins to a UART, such as +//the MAX232N; or a serial->USB cable, such as the FTDI TTL-232R-5V. + +//Connection Diagram: +//[SNES] [UART] [Purpose] +// Latch RXD Data transfer +// Data1 TXD Data transfer +// Data2 RTS Flow control (optional) +// IOBit CTS Flow control (optional) +// GND GND Circuit completion + +//The SNES software program will have to use specially timed code to send and +//receive data at a specific baud-rate; whereas the PC handles timing via the +//UART. + +//The emulator implementation is designed so that the same PC-side program can +//be used both under emulation and on real hardware. It does this by linking to +//a dynamic library for timing, read and write operations. This library is +//responsible for setting both the baud-rate and flow control setting. The +//SNES-side software program must know about and respect the library setting. + +static void snesserial_tick(unsigned clocks); +static uint8 snesserial_read(); +static void snesserial_write(uint8 data); + +void Serial::enter() { + if(enable == false) while(true) step(1); //fallback, in case library was not found + step(256 * 8); //simulate warm-up delay + if(flowcontrol()) data2 = 1; + main(snesserial_tick, snesserial_read, snesserial_write); //stubs for Serial::step, Serial::read, Serial::write + while(true) step(1); //fallback, in case snesserial_main() returns (it should never do so) +} + +uint8 Serial::read() { + while(latched == 0) step(1); + while(latched == 1) step(1); + step(4); + + uint8 data = 0; + for(unsigned i = 0; i < 8; i++) { + step(8); + data = (latched << 7) | (data >> 1); + } + + return data; +} + +void Serial::write(uint8 data) { + if(flowcontrol()) while(iobit()) step(1); + step(8); + + data1 = 1; + step(8); + + for(unsigned i = 0; i < 8; i++) { + data1 = (data & 1) ^ 1; + data >>= 1; + step(8); + } + + data1 = 0; + step(8); +} + +uint2 Serial::data() { + return (data2 << 1) | (data1 << 0); +} + +void Serial::latch(bool data) { + latched = data; +} + +Serial::Serial(bool port) : Controller(port) { + enable = false; + string basename = system.interface->path(Cartridge::Slot::Base, ""); + string name = notdir(basename); + string path = dir(basename); + if(open(name, path)) { + baudrate = sym("snesserial_baudrate"); + flowcontrol = sym("snesserial_flowcontrol"); + main = sym("snesserial_main"); + if(baudrate && flowcontrol && main) enable = true; + } + create(Controller::Enter, enable ? baudrate() * 8 : 1); + + latched = false; + data1 = 0; + data2 = 0; +} + +Serial::~Serial() { + if(opened()) close(); +} + +//stubs needed to call into class objects from global function pointers + +static void snesserial_tick(unsigned clocks) { + if(co_active() == input.port1->thread) { + if(dynamic_cast(input.port1)) { + return ((Serial*)input.port1)->step(clocks); + } + } + + if(co_active() == input.port2->thread) { + if(dynamic_cast(input.port2)) { + return ((Serial*)input.port2)->step(clocks); + } + } +} + +static uint8 snesserial_read() { + if(co_active() == input.port1->thread) { + if(dynamic_cast(input.port1)) { + return ((Serial*)input.port1)->read(); + } + } + + if(co_active() == input.port2->thread) { + if(dynamic_cast(input.port2)) { + return ((Serial*)input.port2)->read(); + } + } + + return 0; +} + +static void snesserial_write(uint8 data) { + if(co_active() == input.port1->thread) { + if(dynamic_cast(input.port1)) { + return ((Serial*)input.port1)->write(data); + } + } + + if(co_active() == input.port2->thread) { + if(dynamic_cast(input.port2)) { + return ((Serial*)input.port2)->write(data); + } + } +} + +#endif diff --git a/snes/controller/serial/serial.hpp b/snes/controller/serial/serial.hpp new file mode 100644 index 0000000..2a68ba5 --- /dev/null +++ b/snes/controller/serial/serial.hpp @@ -0,0 +1,19 @@ +struct Serial : Controller, public library { + void enter(); + uint8 read(); + void write(uint8 data); + uint2 data(); + void latch(bool data); + Serial(bool port); + ~Serial(); + +private: + bool enable; + function baudrate; + function flowcontrol; + function main; + + bool latched; + bool data1; + bool data2; +}; diff --git a/snes/controller/superscope/superscope.cpp b/snes/controller/superscope/superscope.cpp new file mode 100644 index 0000000..b256222 --- /dev/null +++ b/snes/controller/superscope/superscope.cpp @@ -0,0 +1,129 @@ +#ifdef CONTROLLER_CPP + +//The Super Scope is a light-gun: it detects the CRT beam cannon position, +//and latches the counters by toggling iobit. This only works on controller +//port 2, as iobit there is connected to the PPU H/V counter latch. +//(PIO $4201.d7) + +//It is obviously not possible to perfectly simulate an IR light detecting +//a CRT beam cannon, hence this class will read the PPU raster counters. + +//A Super Scope can still technically be used in port 1, however it would +//require manual polling of PIO ($4201.d6) to determine when iobit was written. +//Note that no commercial game ever utilizes a Super Scope in port 1. + +void SuperScope::enter() { + unsigned prev = 0; + while(true) { + unsigned next = cpu.vcounter() * 1364 + cpu.hcounter(); + + if(offscreen == false) { + unsigned target = y * 1364 + (x + 24) * 4; + if(next >= target && prev < target) { + //CRT raster detected, toggle iobit to latch counters + iobit(0); + iobit(1); + } + } + + if(next < prev) { + //Vcounter wrapped back to zero; update cursor coordinates for start of new frame + int nx = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::X); + int ny = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Y); + nx += x; + ny += y; + x = max(-16, min(256 + 16, nx)); + y = max(-16, min(240 + 16, ny)); + offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225)); + } else { + //sleep until PPU counters are close to latch position + unsigned diff = abs((signed)y - cpu.vcounter()); + if(diff >= 2) step((diff - 2) * 1364); + } + + prev = next; + step(2); + } +} + +uint2 SuperScope::data() { + if(counter >= 8) return 1; + + if(counter == 0) { + //turbo is a switch; toggle is edge sensitive + bool newturbo = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Turbo); + if(newturbo && !turbo) { + turbo = !turbo; //toggle state + turbolock = true; + } else { + turbolock = false; + } + + //trigger is a button + //if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive + trigger = false; + bool newtrigger = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Trigger); + if(newtrigger && (turbo || !triggerlock)) { + trigger = true; + triggerlock = true; + } else if(!newtrigger) { + triggerlock = false; + } + + //cursor is a button; it is always level sensitive + cursor = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Cursor); + + //pause is a button; it is always edge sensitive + pause = false; + bool newpause = system.interface->input_poll(port, Input::Device::SuperScope, 0, (unsigned)Input::SuperScopeID::Pause); + if(newpause && !pauselock) { + pause = true; + pauselock = true; + } else if(!newpause) { + pauselock = false; + } + + offscreen = (x < 0 || y < 0 || x >= 256 || y >= (ppu.overscan() ? 240 : 225)); + } + + switch(counter++) { + case 0: return offscreen ? 0 : trigger; + case 1: return cursor; + case 2: return turbo; + case 3: return pause; + case 4: return 0; + case 5: return 0; + case 6: return offscreen; + case 7: return 0; //noise (1 = yes) + } + + return 0; +} + +void SuperScope::latch(bool data) { + if(latched == data) return; + latched = data; + counter = 0; +} + +SuperScope::SuperScope(bool port) : Controller(port) { + create(Controller::Enter, 21477272); + latched = 0; + counter = 0; + + //center cursor onscreen + x = 256 / 2; + y = 240 / 2; + + trigger = false; + cursor = false; + turbo = false; + pause = false; + offscreen = false; + + turbolock = false; + triggerlock = false; + pauselock = false; +} + +#endif diff --git a/snes/controller/superscope/superscope.hpp b/snes/controller/superscope/superscope.hpp new file mode 100644 index 0000000..a7a90b7 --- /dev/null +++ b/snes/controller/superscope/superscope.hpp @@ -0,0 +1,22 @@ +struct SuperScope : Controller { + void enter(); + uint2 data(); + void latch(bool data); + SuperScope(bool port); + +//private: + bool latched; + unsigned counter; + + signed x, y; + + bool trigger; + bool cursor; + bool turbo; + bool pause; + bool offscreen; + + bool turbolock; + bool triggerlock; + bool pauselock; +}; diff --git a/snes/cpu/cpu.cpp b/snes/cpu/cpu.cpp index aada28d..21955c6 100644 --- a/snes/cpu/cpu.cpp +++ b/snes/cpu/cpu.cpp @@ -23,6 +23,9 @@ void CPU::step(unsigned clocks) { Processor &chip = *coprocessors[i]; chip.clock -= clocks * (uint64)chip.frequency; } + input.port1->clock -= clocks * (uint64)input.port1->frequency; + input.port2->clock -= clocks * (uint64)input.port2->frequency; + synchronize_controllers(); } void CPU::synchronize_smp() { @@ -41,13 +44,18 @@ void CPU::synchronize_ppu() { } } -void CPU::synchronize_coprocessor() { +void CPU::synchronize_coprocessors() { for(unsigned i = 0; i < coprocessors.size(); i++) { Processor &chip = *coprocessors[i]; if(chip.clock < 0) co_switch(chip.thread); } } +void CPU::synchronize_controllers() { + if(input.port1->clock < 0) co_switch(input.port1->thread); + if(input.port2->clock < 0) co_switch(input.port2->thread); +} + void CPU::Enter() { cpu.enter(); } void CPU::enter() { diff --git a/snes/cpu/cpu.hpp b/snes/cpu/cpu.hpp index ca24a9e..2543f7e 100644 --- a/snes/cpu/cpu.hpp +++ b/snes/cpu/cpu.hpp @@ -7,7 +7,8 @@ public: alwaysinline void step(unsigned clocks); alwaysinline void synchronize_smp(); void synchronize_ppu(); - void synchronize_coprocessor(); + void synchronize_coprocessors(); + void synchronize_controllers(); uint8 port_read(uint2 port) const; void port_write(uint2 port, uint8 data); diff --git a/snes/cpu/mmio/mmio.cpp b/snes/cpu/mmio/mmio.cpp index 2d69bcb..6cf8111 100644 --- a/snes/cpu/mmio/mmio.cpp +++ b/snes/cpu/mmio/mmio.cpp @@ -33,10 +33,8 @@ void CPU::mmio_w2183(uint8 data) { //strobing $4016.d0 affects both controller port latches. //$4017 bit 0 writes are ignored. void CPU::mmio_w4016(uint8 data) { - bool old_latch = status.joypad_strobe_latch; - bool new_latch = data & 1; - status.joypad_strobe_latch = new_latch; - if(old_latch != new_latch) input.poll(); + input.port1->latch(data & 1); + input.port2->latch(data & 1); } //JOYSER0 @@ -44,7 +42,7 @@ void CPU::mmio_w4016(uint8 data) { //1-0 = Joypad serial data uint8 CPU::mmio_r4016() { uint8 r = regs.mdr & 0xfc; - r |= input.port_read(0) & 3; + r |= input.port1->data(); return r; } @@ -54,7 +52,7 @@ uint8 CPU::mmio_r4016() { //1-0 = Joypad serial data uint8 CPU::mmio_r4017() { uint8 r = (regs.mdr & 0xe0) | 0x1c; - r |= input.port_read(1) & 3; + r |= input.port2->data(); return r; } diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp index bd694b3..6e15346 100644 --- a/snes/cpu/timing/joypad.cpp +++ b/snes/cpu/timing/joypad.cpp @@ -6,10 +6,15 @@ void CPU::step_auto_joypad_poll() { status.auto_joypad_active = status.auto_joypad_counter <= 15; if(status.auto_joypad_active && status.auto_joypad_poll) { - if(status.auto_joypad_counter == 0) input.poll(); + if(status.auto_joypad_counter == 0) { + input.port1->latch(1); + input.port2->latch(1); + input.port1->latch(0); + input.port2->latch(0); + } - uint8 port0 = input.port_read(0); - uint8 port1 = input.port_read(1); + uint2 port0 = input.port1->data(); + uint2 port1 = input.port2->data(); status.joy1 = (status.joy1 << 1) | (bool)(port0 & 1); status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1); diff --git a/snes/cpu/timing/timing.cpp b/snes/cpu/timing/timing.cpp index b4b07aa..c569e94 100644 --- a/snes/cpu/timing/timing.cpp +++ b/snes/cpu/timing/timing.cpp @@ -12,10 +12,7 @@ void CPU::add_clocks(unsigned clocks) { unsigned ticks = clocks >> 1; while(ticks--) { tick(); - if(hcounter() & 2) { - input.tick(); - poll_interrupts(); - } + if(hcounter() & 2) poll_interrupts(); } step(clocks); @@ -40,7 +37,7 @@ void CPU::scanline() { //forcefully sync S-CPU to other processors, in case chips are not communicating synchronize_ppu(); synchronize_smp(); - synchronize_coprocessor(); + synchronize_coprocessors(); system.scanline(); if(vcounter() == 0) { diff --git a/snes/input/input.cpp b/snes/input/input.cpp index 40a9df7..2d548bc 100644 --- a/snes/input/input.cpp +++ b/snes/input/input.cpp @@ -2,348 +2,38 @@ Input input; -uint8 Input::port_read(bool portnumber) { - if(cartridge.has_serial() && portnumber == 1) { - return (serial.data2() << 1) | (serial.data1() << 0); +void Input::connect(bool port, Input::Device::e id) { + Controller *&controller = ((port ? 1 : 0) == Controller::Port1 ? port1 : port2); + if(controller) { + delete controller; + controller = 0; } - port_t &p = port[portnumber]; - - switch(p.device.i) { - case Device::Joypad: { - if(cpu.joylatch() == 0) { - if(p.counter0 >= 16) return 1; - return system.interface->input_poll(portnumber, p.device.i, 0, p.counter0++); - } else { - return system.interface->input_poll(portnumber, p.device.i, 0, 0); - } - } //case Device::Joypad - - case Device::Multitap: { - if(cpu.joylatch()) return 2; //when latch is high -- data2 = 1, data1 = 0 - - unsigned deviceidx, deviceindex0, deviceindex1; - uint8 mask = (portnumber == 0 ? 0x40 : 0x80); - - if(cpu.pio() & mask) { - deviceidx = p.counter0; - if(deviceidx >= 16) return 3; - p.counter0++; - - deviceindex0 = 0; //controller 1 - deviceindex1 = 1; //controller 2 - } else { - deviceidx = p.counter1; - if(deviceidx >= 16) return 3; - p.counter1++; - - deviceindex0 = 2; //controller 3 - deviceindex1 = 3; //controller 4 - } - - return (system.interface->input_poll(portnumber, p.device.i, deviceindex0, deviceidx) << 0) - | (system.interface->input_poll(portnumber, p.device.i, deviceindex1, deviceidx) << 1); - } //case Device::Multitap - - case Device::Mouse: { - if(p.counter0 >= 32) return 1; - - int position_x = system.interface->input_poll(portnumber, p.device.i, 0, (unsigned)MouseID::X); //-n = left, 0 = center, +n = right - int position_y = system.interface->input_poll(portnumber, p.device.i, 0, (unsigned)MouseID::Y); //-n = up, 0 = center, +n = right - - bool direction_x = position_x < 0; //0 = right, 1 = left - bool direction_y = position_y < 0; //0 = down, 1 = up - - if(position_x < 0) position_x = -position_x; //abs(position_x) - if(position_y < 0) position_y = -position_y; //abs(position_x) - - position_x = min(127, position_x); //range = 0 - 127 - position_y = min(127, position_y); //range = 0 - 127 - - switch(p.counter0++) { default: - case 0: return 0; - case 1: return 0; - case 2: return 0; - case 3: return 0; - case 4: return 0; - case 5: return 0; - case 6: return 0; - case 7: return 0; - - case 8: return system.interface->input_poll(portnumber, p.device.i, 0, (unsigned)MouseID::Right); - case 9: return system.interface->input_poll(portnumber, p.device.i, 0, (unsigned)MouseID::Left); - case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused) - case 11: return 0; // || - - case 12: return 0; //signature - case 13: return 0; // || - case 14: return 0; // || - case 15: return 1; // || - - case 16: return (direction_y) & 1; - case 17: return (position_y >> 6) & 1; - case 18: return (position_y >> 5) & 1; - case 19: return (position_y >> 4) & 1; - case 20: return (position_y >> 3) & 1; - case 21: return (position_y >> 2) & 1; - case 22: return (position_y >> 1) & 1; - case 23: return (position_y >> 0) & 1; - - case 24: return (direction_x) & 1; - case 25: return (position_x >> 6) & 1; - case 26: return (position_x >> 5) & 1; - case 27: return (position_x >> 4) & 1; - case 28: return (position_x >> 3) & 1; - case 29: return (position_x >> 2) & 1; - case 30: return (position_x >> 1) & 1; - case 31: return (position_x >> 0) & 1; - } - } //case Device::Mouse - - case Device::SuperScope: { - if(portnumber == 0) break; //Super Scope in port 1 not supported ... - if(p.counter0 >= 8) return 1; - - if(p.counter0 == 0) { - //turbo is a switch; toggle is edge sensitive - bool turbo = system.interface->input_poll(portnumber, p.device.i, 0, (unsigned)SuperScopeID::Turbo); - if(turbo && !p.superscope.turbolock) { - p.superscope.turbo = !p.superscope.turbo; //toggle state - p.superscope.turbolock = true; - } else if(!turbo) { - p.superscope.turbolock = false; - } - - //trigger is a button - //if turbo is active, trigger is level sensitive; otherwise it is edge sensitive - p.superscope.trigger = false; - bool trigger = system.interface->input_poll(portnumber, p.device.i, 0, (unsigned)SuperScopeID::Trigger); - if(trigger && (p.superscope.turbo || !p.superscope.triggerlock)) { - p.superscope.trigger = true; - p.superscope.triggerlock = true; - } else if(!trigger) { - p.superscope.triggerlock = false; - } - - //cursor is a button; it is always level sensitive - p.superscope.cursor = system.interface->input_poll(portnumber, p.device.i, 0, (unsigned)SuperScopeID::Cursor); - - //pause is a button; it is always edge sensitive - p.superscope.pause = false; - bool pause = system.interface->input_poll(portnumber, p.device.i, 0, (unsigned)SuperScopeID::Pause); - if(pause && !p.superscope.pauselock) { - p.superscope.pause = true; - p.superscope.pauselock = true; - } else if(!pause) { - p.superscope.pauselock = false; - } - - p.superscope.offscreen = - p.superscope.x < 0 || p.superscope.x >= 256 - || p.superscope.y < 0 || p.superscope.y >= (ppu.overscan() ? 240 : 225); - } - - switch(p.counter0++) { - case 0: return p.superscope.trigger; - case 1: return p.superscope.cursor; - case 2: return p.superscope.turbo; - case 3: return p.superscope.pause; - case 4: return 0; - case 5: return 0; - case 6: return p.superscope.offscreen; - case 7: return 0; //noise (1 = yes) - } - } //case Device::SuperScope - - case Device::Justifier: - case Device::Justifiers: { - if(portnumber == 0) break; //Justifier in port 1 not supported ... - if(p.counter0 >= 32) return 1; - - if(p.counter0 == 0) { - p.justifier.trigger1 = system.interface->input_poll(portnumber, p.device.i, 0, (unsigned)JustifierID::Trigger); - p.justifier.start1 = system.interface->input_poll(portnumber, p.device.i, 0, (unsigned)JustifierID::Start); - - if(p.device.i == Device::Justifiers) { - p.justifier.trigger2 = system.interface->input_poll(portnumber, p.device.i, 1, (unsigned)JustifierID::Trigger); - p.justifier.start2 = system.interface->input_poll(portnumber, p.device.i, 1, (unsigned)JustifierID::Start); - } else { - p.justifier.x2 = -1; - p.justifier.y2 = -1; - - p.justifier.trigger2 = false; - p.justifier.start2 = false; - } - } - - switch(p.counter0++) { - case 0: return 0; - case 1: return 0; - case 2: return 0; - case 3: return 0; - case 4: return 0; - case 5: return 0; - case 6: return 0; - case 7: return 0; - case 8: return 0; - case 9: return 0; - case 10: return 0; - case 11: return 0; - - case 12: return 1; //signature - case 13: return 1; // || - case 14: return 1; // || - case 15: return 0; // || - - case 16: return 0; - case 17: return 1; - case 18: return 0; - case 19: return 1; - case 20: return 0; - case 21: return 1; - case 22: return 0; - case 23: return 1; - - case 24: return p.justifier.trigger1; - case 25: return p.justifier.trigger2; - case 26: return p.justifier.start1; - case 27: return p.justifier.start2; - case 28: return p.justifier.active; - - case 29: return 0; - case 30: return 0; - case 31: return 0; - } - - default: - break; - } //case Device::Justifier(s) - } //switch(p.device.i) - - //no device connected - return 0; -} - -//scan all input; update cursor positions if needed -void Input::update() { - system.interface->input_poll(); - port_t &p = port[1]; - - switch(p.device.i) { - case Device::SuperScope: { - int x = system.interface->input_poll(1, p.device.i, 0, (unsigned)SuperScopeID::X); - int y = system.interface->input_poll(1, p.device.i, 0, (unsigned)SuperScopeID::Y); - x += p.superscope.x; - y += p.superscope.y; - p.superscope.x = max(-16, min(256 + 16, x)); - p.superscope.y = max(-16, min(240 + 16, y)); - - latchx = p.superscope.x; - latchy = p.superscope.y; - } break; - - case Device::Justifier: - case Device::Justifiers: { - int x1 = system.interface->input_poll(1, p.device.i, 0, (unsigned)JustifierID::X); - int y1 = system.interface->input_poll(1, p.device.i, 0, (unsigned)JustifierID::Y); - x1 += p.justifier.x1; - y1 += p.justifier.y1; - p.justifier.x1 = max(-16, min(256 + 16, x1)); - p.justifier.y1 = max(-16, min(240 + 16, y1)); - - int x2 = system.interface->input_poll(1, p.device.i, 1, (unsigned)JustifierID::X); - int y2 = system.interface->input_poll(1, p.device.i, 1, (unsigned)JustifierID::Y); - x2 += p.justifier.x2; - y2 += p.justifier.y2; - p.justifier.x2 = max(-16, min(256 + 16, x2)); - p.justifier.y2 = max(-16, min(240 + 16, y2)); - - if(p.justifier.active == 0) { - latchx = p.justifier.x1; - latchy = p.justifier.y1; - } else { - latchx = (p.device.i == Device::Justifiers ? p.justifier.x2 : -1); - latchy = (p.device.i == Device::Justifiers ? p.justifier.y2 : -1); - } - } break; - default: - break; + switch(id) { default: + case Device::None: controller = new Controller(port); break; + case Device::Joypad: controller = new Gamepad(port); break; + case Device::Multitap: controller = new Multitap(port); break; + case Device::Mouse: controller = new Mouse(port); break; + case Device::SuperScope: controller = new SuperScope(port); break; + case Device::Justifier: controller = new Justifier(port, false); break; + case Device::Justifiers: controller = new Justifier(port, true); break; + case Device::Serial: controller = new Serial(port); break; } - if(latchy < 0 || latchy >= (ppu.overscan() ? 240 : 225) || latchx < 0 || latchx >= 256) { - //cursor is offscreen, set to invalid position so counters are not latched - latchx = ~0; - latchy = ~0; - } else { - //cursor is onscreen - latchx += 40; //offset trigger position to simulate hardware latching delay - latchx <<= 2; //dot -> clock conversion - latchx += 2; //align trigger on half-dot ala interrupts (speed optimization for sCPU::add_clocks) + switch(port ? 1 : 0) { + case Controller::Port1: config.controller_port1.i = id; break; + case Controller::Port2: config.controller_port2.i = id; break; } } -void Input::port_set_device(bool portnumber, Device::e device) { - port_t &p = port[portnumber]; - - p.device.i = device; - p.counter0 = 0; - p.counter1 = 0; - - //set iobit to true if device is capable of latching PPU counters - iobit = port[1].device.i == Device::SuperScope - || port[1].device.i == Device::Justifier - || port[1].device.i == Device::Justifiers; - latchx = -1; - latchy = -1; - - if(device == Device::SuperScope) { - p.superscope.x = 256 / 2; - p.superscope.y = 240 / 2; - - p.superscope.trigger = false; - p.superscope.cursor = false; - p.superscope.turbo = false; - p.superscope.pause = false; - p.superscope.offscreen = false; - - p.superscope.turbolock = false; - p.superscope.triggerlock = false; - p.superscope.pauselock = false; - } else if(device == Device::Justifier) { - p.justifier.active = 0; - p.justifier.x1 = 256 / 2; - p.justifier.y1 = 240 / 2; - p.justifier.x2 = -1; - p.justifier.y2 = -1; - - p.justifier.trigger1 = false; - p.justifier.trigger2 = false; - p.justifier.start1 = false; - p.justifier.start2 = false; - } else if(device == Device::Justifiers) { - p.justifier.active = 0; - p.justifier.x1 = 256 / 2 - 16; - p.justifier.y1 = 240 / 2; - p.justifier.x2 = 256 / 2 + 16; - p.justifier.y2 = 240 / 2; - - p.justifier.trigger1 = false; - p.justifier.trigger2 = false; - p.justifier.start1 = false; - p.justifier.start2 = false; - } +Input::Input() { + connect(Controller::Port1, Input::Device::Joypad); + connect(Controller::Port2, Input::Device::Joypad); } -void Input::poll() { - port[0].counter0 = 0; - port[0].counter1 = 0; - port[1].counter0 = 0; - port[1].counter1 = 0; - - port[1].justifier.active = !port[1].justifier.active; -} - -void Input::init() { +Input::~Input() { + if(port1) delete port1; + if(port2) delete port2; } #endif diff --git a/snes/input/input.hpp b/snes/input/input.hpp index af83692..caca5b1 100644 --- a/snes/input/input.hpp +++ b/snes/input/input.hpp @@ -1,98 +1,49 @@ -class Input { -public: +struct Input { struct Device { - enum e { - None, - Joypad, - Multitap, - Mouse, - SuperScope, - Justifier, - Justifiers, - } i; + enum e { + None, + Joypad, + Multitap, + Mouse, + SuperScope, + Justifier, + Justifiers, + Serial, + } i; }; struct JoypadID { - enum e { - B = 0, Y = 1, Select = 2, Start = 3, - Up = 4, Down = 5, Left = 6, Right = 7, - A = 8, X = 9, L = 10, R = 11, - } i; + enum e { + B = 0, Y = 1, Select = 2, Start = 3, + Up = 4, Down = 5, Left = 6, Right = 7, + A = 8, X = 9, L = 10, R = 11, + } i; }; struct MouseID { - enum e { - X = 0, Y = 1, Left = 2, Right = 3, - } i; + enum e { + X = 0, Y = 1, Left = 2, Right = 3, + } i; }; struct SuperScopeID { - enum e { - X = 0, Y = 1, Trigger = 2, Cursor = 3, Turbo = 4, Pause = 5, - } i; + enum e { + X = 0, Y = 1, Trigger = 2, Cursor = 3, Turbo = 4, Pause = 5, + } i; }; struct JustifierID { - enum e { - X = 0, Y = 1, Trigger = 2, Start = 3, - } i; + enum e { + X = 0, Y = 1, Trigger = 2, Start = 3, + } i; }; - uint8 port_read(bool port); - void port_set_device(bool port, Device::e device); - void init(); - void poll(); - void update(); + Controller *port1; + Controller *port2; - //light guns (Super Scope, Justifier(s)) strobe IOBit whenever the CRT - //beam cannon is detected. this needs to be tested at the cycle level - //(hence inlining here for speed) to avoid 'dead space' during DRAM refresh. - //iobit is updated during port_set_device(), - //latchx, latchy are updated during update() (once per frame) - alwaysinline void tick() { - //only test if Super Scope or Justifier is connected - if(iobit && cpu.vcounter() == latchy && cpu.hcounter() == latchx) { - ppu.latch_counters(); - } - } - -private: - bool iobit; - int16_t latchx, latchy; - - struct port_t { - Device device; - unsigned counter0; //read counters - unsigned counter1; - - struct superscope_t { - int x, y; - - bool trigger; - bool cursor; - bool turbo; - bool pause; - bool offscreen; - - bool turbolock; - bool triggerlock; - bool pauselock; - } superscope; - - struct justifier_t { - bool active; - - int x1, x2; - int y1, y2; - - bool trigger1, trigger2; - bool start1, start2; - } justifier; - } port[2]; - - friend class System; - friend class Video; - friend class CPU; + void connect(bool port, Input::Device::e id); + Input(); + ~Input(); }; extern Input input; diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp index b14789c..ccd49f9 100644 --- a/snes/interface/interface.hpp +++ b/snes/interface/interface.hpp @@ -1,9 +1,9 @@ class Interface { public: - virtual void video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan) {} - virtual void audio_sample(uint16_t l_sample, uint16_t r_sample) {} - virtual void input_poll() {} - virtual int16_t input_poll(bool port, Input::Device::e device, unsigned index, unsigned id) { return 0; } + virtual void video_refresh(const uint16_t *data, bool hires, bool interlace, bool overscan) = 0; + virtual void audio_sample(uint16_t l_sample, uint16_t r_sample) = 0; + virtual void input_poll() = 0; + virtual int16_t input_poll(bool port, Input::Device::e device, unsigned index, unsigned id) = 0; virtual void message(const string &text) { print(text, "\n"); } virtual string path(Cartridge::Slot::e slot, const string &hint) = 0; diff --git a/snes/libsnes/libsnes.cpp b/snes/libsnes/libsnes.cpp index 0fc1909..6a5551a 100644 --- a/snes/libsnes/libsnes.cpp +++ b/snes/libsnes/libsnes.cpp @@ -77,7 +77,7 @@ void snes_set_input_state(snes_input_state_t input_state) { } void snes_set_controller_port_device(bool port, unsigned device) { - SNES::input.port_set_device(port, (SNES::Input::Device::e)device); + SNES::input.connect(port, (SNES::Input::Device::e)device); } void snes_set_cartridge_basename(const char *basename) { @@ -86,8 +86,8 @@ void snes_set_cartridge_basename(const char *basename) { void snes_init(void) { SNES::system.init(&interface); - SNES::input.port_set_device(0, SNES::Input::Device::Joypad); - SNES::input.port_set_device(1, SNES::Input::Device::Joypad); + SNES::input.connect(0, SNES::Input::Device::Joypad); + SNES::input.connect(1, SNES::Input::Device::Joypad); } void snes_term(void) { diff --git a/snes/libsnes/libsnes.hpp b/snes/libsnes/libsnes.hpp index 1b9293a..a42bd99 100644 --- a/snes/libsnes/libsnes.hpp +++ b/snes/libsnes/libsnes.hpp @@ -61,6 +61,7 @@ extern "C" { #define SNES_DEVICE_SUPER_SCOPE 4 #define SNES_DEVICE_JUSTIFIER 5 #define SNES_DEVICE_JUSTIFIERS 6 +#define SNES_DEVICE_SERIAL_CABLE 7 // These constants represent the button and axis inputs on various controllers, // for use with the snes_input_state_t callback. diff --git a/snes/memory/memory-inline.hpp b/snes/memory/memory-inline.hpp index 7a9e340..70503be 100644 --- a/snes/memory/memory-inline.hpp +++ b/snes/memory/memory-inline.hpp @@ -52,6 +52,7 @@ MappedRAM::MappedRAM() : data_(0), size_(0), write_protect_(false) {} //Bus uint8 Bus::read(unsigned addr) { + if(cheat.override[addr]) return cheat.read(addr); return reader[lookup[addr]](target[addr]); } diff --git a/snes/snes.hpp b/snes/snes.hpp index 7bb1d87..85f8139 100644 --- a/snes/snes.hpp +++ b/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "079.04"; + static const char Version[] = "080"; static const unsigned SerializerVersion = 21; } } @@ -129,6 +129,7 @@ namespace SNES { #include "profile-performance.hpp" #endif + #include #include #include #include diff --git a/snes/system/serialization.cpp b/snes/system/serialization.cpp index ac6365d..0b0a7c0 100755 --- a/snes/system/serialization.cpp +++ b/snes/system/serialization.cpp @@ -68,7 +68,6 @@ void System::serialize_all(serializer &s) { if(cartridge.has_spc7110()) spc7110.serialize(s); if(cartridge.has_obc1()) obc1.serialize(s); if(cartridge.has_msu1()) msu1.serialize(s); - if(cartridge.has_serial()) serial.serialize(s); } //perform dry-run state save: diff --git a/snes/system/system.cpp b/snes/system/system.cpp index 649dde9..0acc300 100755 --- a/snes/system/system.cpp +++ b/snes/system/system.cpp @@ -21,7 +21,6 @@ void System::run() { scheduler.enter(); if(scheduler.exit_reason.i == Scheduler::ExitReason::FrameEvent) { - input.update(); video.update(); } } @@ -59,7 +58,6 @@ void System::runthreadtosave() { scheduler.enter(); if(scheduler.exit_reason.i == Scheduler::ExitReason::SynchronizeEvent) break; if(scheduler.exit_reason.i == Scheduler::ExitReason::FrameEvent) { - input.update(); video.update(); } } @@ -84,15 +82,13 @@ void System::init(Interface *interface_) { obc1.init(); st0018.init(); msu1.init(); - serial.init(); link.init(); video.init(); audio.init(); - input.init(); - input.port_set_device(0, config.controller_port1.i); - input.port_set_device(1, config.controller_port2.i); + input.connect(0, config.controller_port1.i); + input.connect(1, config.controller_port2.i); } void System::term() { @@ -124,7 +120,6 @@ void System::load() { if(cartridge.has_obc1()) obc1.load(); if(cartridge.has_st0018()) st0018.load(); if(cartridge.has_msu1()) msu1.load(); - if(cartridge.has_serial()) serial.load(); if(cartridge.has_link()) link.load(); serialize_init(); @@ -149,7 +144,6 @@ void System::unload() { if(cartridge.has_obc1()) obc1.unload(); if(cartridge.has_st0018()) st0018.unload(); if(cartridge.has_msu1()) msu1.unload(); - if(cartridge.has_serial()) serial.unload(); if(cartridge.has_link()) link.unload(); } @@ -186,7 +180,6 @@ void System::power() { if(cartridge.has_obc1()) obc1.power(); if(cartridge.has_st0018()) st0018.power(); if(cartridge.has_msu1()) msu1.power(); - if(cartridge.has_serial()) serial.power(); if(cartridge.has_link()) link.power(); if(cartridge.mode.i == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2); @@ -195,11 +188,11 @@ void System::power() { if(cartridge.has_necdsp()) cpu.coprocessors.append(&necdsp); if(cartridge.has_hitachidsp()) cpu.coprocessors.append(&hitachidsp); if(cartridge.has_msu1()) cpu.coprocessors.append(&msu1); - if(cartridge.has_serial()) cpu.coprocessors.append(&serial); if(cartridge.has_link()) cpu.coprocessors.append(&link); scheduler.init(); - input.update(); + input.connect(0, config.controller_port1.i); + input.connect(1, config.controller_port2.i); } void System::reset() { @@ -225,7 +218,6 @@ void System::reset() { if(cartridge.has_obc1()) obc1.reset(); if(cartridge.has_st0018()) st0018.reset(); if(cartridge.has_msu1()) msu1.reset(); - if(cartridge.has_serial()) serial.reset(); if(cartridge.has_link()) link.reset(); if(cartridge.mode.i == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2); @@ -234,13 +226,11 @@ void System::reset() { if(cartridge.has_necdsp()) cpu.coprocessors.append(&necdsp); if(cartridge.has_hitachidsp()) cpu.coprocessors.append(&hitachidsp); if(cartridge.has_msu1()) cpu.coprocessors.append(&msu1); - if(cartridge.has_serial()) cpu.coprocessors.append(&serial); if(cartridge.has_link()) cpu.coprocessors.append(&link); scheduler.init(); - input.port_set_device(0, config.controller_port1.i); - input.port_set_device(1, config.controller_port2.i); - input.update(); + input.connect(0, config.controller_port1.i); + input.connect(1, config.controller_port2.i); } void System::scanline() { diff --git a/snes/video/video.cpp b/snes/video/video.cpp index b393480..c2a27b1 100644 --- a/snes/video/video.cpp +++ b/snes/video/video.cpp @@ -47,14 +47,24 @@ void Video::draw_cursor(uint16_t color, int x, int y) { } void Video::update() { - switch(input.port[1].device.i) { - case Input::Device::SuperScope: draw_cursor(0x001f, input.port[1].superscope.x, input.port[1].superscope.y); break; - case Input::Device::Justifiers: draw_cursor(0x02e0, input.port[1].justifier.x2, input.port[1].justifier.y2); //fallthrough - case Input::Device::Justifier: draw_cursor(0x001f, input.port[1].justifier.x1, input.port[1].justifier.y1); break; - case Input::Device::None: - case Input::Device::Joypad: - case Input::Device::Mouse: - case Input::Device::Multitap: break; + switch(config.controller_port2.i) { + case Input::Device::SuperScope: + if(dynamic_cast(input.port2)) { + SuperScope &device = (SuperScope&)*input.port2; + draw_cursor(0x7c00, device.x, device.y); + } + break; + case Input::Device::Justifier: + case Input::Device::Justifiers: + if(dynamic_cast(input.port2)) { + Justifier &device = (Justifier&)*input.port2; + draw_cursor(0x001f, device.x1, device.y1); + if(device.chained == false) break; + draw_cursor(0x02e0, device.x2, device.y2); + } + break; + default: + break; } uint16_t *data = (uint16_t*)ppu.output;