From 5fc86eae6d9b40ff8d117c6fc6cbae6bcd288419 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sun, 26 Jun 2011 22:51:37 +1000 Subject: [PATCH] Update to v080 release. byuu says: This release adds low-level emulation of the Hitachi HG51B169 DSP, which was used in Mega Man X2 and Mega Man X3 as the Cx4 chip. It also fixes a regression in both the sound core and cheat engine. You will now need the HG51B169 data ROM to play MMX2/MMX3. Once again, Cx4 LLE could not have been possible without the help of Dr. Decapitator, Jonas Quinn, Overload and Segher. Be sure to thank them, please! Changelog: * added Cx4 low-level emulation; removed Cx4 high-level emulation code * fixed S-SMP synchronization to S-CPU on CPUIO writes * controllers now have their own threads and classes * serial controller is now emulated as an actual controller, rather than as a coprocessor * added link coprocessor module for special chip research and homebrew * fixed cheat codes that target mask ROM addresses [Cydrak] * fixed compilation error with the latest GCC 4.6.0 beta releases * added flexibility to XML memory mapping file format * updated to mightymo's latest cheat pack (2011-06-20) --- bsnes/Makefile | 2 +- bsnes/data/cheats.xml | 247 +++++++++++++++--- bsnes/nall/snes/cartridge.hpp | 62 ++--- bsnes/snes/Makefile | 3 +- bsnes/snes/alt/cpu/cpu.cpp | 10 +- bsnes/snes/alt/cpu/cpu.hpp | 4 +- bsnes/snes/alt/cpu/mmio.cpp | 10 +- bsnes/snes/alt/cpu/timing.cpp | 17 +- bsnes/snes/cartridge/cartridge.cpp | 3 +- bsnes/snes/cartridge/cartridge.hpp | 4 +- bsnes/snes/cartridge/xml.cpp | 128 ++++----- bsnes/snes/cheat/cheat.cpp | 23 +- bsnes/snes/cheat/cheat.hpp | 2 +- bsnes/snes/chip/chip.hpp | 1 - bsnes/snes/chip/serial/serial.cpp | 107 -------- bsnes/snes/chip/serial/serial.hpp | 28 -- bsnes/snes/chip/serial/serialization.cpp | 9 - bsnes/snes/controller/controller.cpp | 1 + bsnes/snes/controller/controller.hpp | 1 + bsnes/snes/controller/justifier/justifier.cpp | 32 +-- bsnes/snes/controller/justifier/justifier.hpp | 1 - bsnes/snes/controller/serial/serial.cpp | 146 +++++++++++ bsnes/snes/controller/serial/serial.hpp | 19 ++ .../snes/controller/superscope/superscope.cpp | 24 +- .../snes/controller/superscope/superscope.hpp | 2 +- bsnes/snes/cpu/timing/joypad.cpp | 2 - bsnes/snes/cpu/timing/timing.cpp | 5 +- bsnes/snes/input/input.cpp | 1 + bsnes/snes/input/input.hpp | 1 + bsnes/snes/memory/memory-inline.hpp | 1 + bsnes/snes/snes.hpp | 2 +- bsnes/snes/system/serialization.cpp | 1 - bsnes/snes/system/system.cpp | 7 - bsnes/ui-libsnes/libsnes.cpp | 6 +- bsnes/ui-libsnes/libsnes.hpp | 15 +- bsnes/ui/general/main-window.cpp | 8 +- bsnes/ui/general/main-window.hpp | 1 + bsnes/ui/main.cpp | 1 + bsnes/ui/utility/utility.cpp | 1 + 39 files changed, 569 insertions(+), 369 deletions(-) delete mode 100755 bsnes/snes/chip/serial/serial.cpp delete mode 100755 bsnes/snes/chip/serial/serial.hpp delete mode 100755 bsnes/snes/chip/serial/serialization.cpp create mode 100755 bsnes/snes/controller/serial/serial.cpp create mode 100755 bsnes/snes/controller/serial/serial.hpp diff --git a/bsnes/Makefile b/bsnes/Makefile index 4af87086..0ae818e5 100755 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -1,7 +1,7 @@ include nall/Makefile snes := snes gameboy := gameboy -profile := accuracy +profile := compatibility ui := ui # debugger diff --git a/bsnes/data/cheats.xml b/bsnes/data/cheats.xml index b49542f4..d82bc1ed 100755 --- a/bsnes/data/cheats.xml +++ b/bsnes/data/cheats.xml @@ -3013,6 +3013,11 @@ Alien vs. Predator (USA) + + Invincibility + 1D3B-0FAD + 6D22-D4D7 + Infinite health C238-0FDD @@ -3043,10 +3048,18 @@ 3CEA-67D8 - One hit kills most enemies - DFB5-AD67 - 7E1125FF - 7E1AA5FF + One hit kills + 6D2D-AFA7 + 6D37-64DD + 6DB8-A765 + 6D39-DD6F + + + Hit anywhere + 402B-6FD7 + D12B-0D07 + D12D-0D67 + D13A-A4DD Disc power-ups give 1 disc instead of 6 (handicap) @@ -9024,20 +9037,20 @@ Combatribes, The (USA) - Invincibility + Invincibility - both players 2DB1-A7D4 - Infinite health + Invincibility - P1 + 7E193401 + + + Infinite health - both players 3CB5-6F64 CBB5-6FA4 A6B5-64D4 62B5-6464 - - Infinite credits - A2B3-A404 - Infinite health - P1 7E1794C8 @@ -9046,12 +9059,24 @@ Infinite health - P2 7E1796C8 + + Infinite credits + A2B3-A404 + Infinite credits (alt) 7E156409 - One hit kills + Hit anywhere - P1 + 3DBB-076D + 70BC-0D6D + DDBB-07AD + DDBC-0DDD + EDBC-0D0D + + + One hit kills - both players 3DA3-64AF DDA3-67DF DDA3-670F @@ -12230,7 +12255,7 @@ BAC9-3FBF - Pick up to 9 points of any attribute instead of 5 + 9 points of any attribute instead of 5 DBBC-1F27 @@ -17467,6 +17492,12 @@ CBE8-47AF EEEA-4DDF + + Hit anywhere - both players + 4062-1DA6 + 4062-14D6 + 406C-1DA6 + Both players can select same character 33C5-1404 @@ -17554,13 +17585,6 @@ Infinite time C2F9-84DF - - Instant super energy - CBB5-5D07 - 46B5-5D67 - DDB5-5DA7 - 4BB5-5F07 - Infinite super energy - P1 7E051663 @@ -17577,6 +17601,19 @@ Infinite throw time - P2 7E068010 + + Hit anywhere - both players + 3DA7-E76D + D5A0-EDDD + DDA7-E7AD + + + Instant super energy + CBB5-5D07 + 46B5-5D67 + DDB5-5DA7 + 4BB5-5F07 + Have the Pipe - P1 7E051401 @@ -18103,6 +18140,16 @@ DDE3-0FAC + + Foreman For Real (USA) + + Infinite stamina - P1 + 7E11AE64 + 7E107227 + 7E043A78 + 7E045A64 + + Fun 'n Games (USA) @@ -36725,6 +36772,14 @@ Infinite Boomerangs DDA5-3700 + + Walk through walls + 6D64-CDAF + + + Jump through ceilings + 6D68-1FD4 + Get 2x energy from sacred hearts 746B-4D6A @@ -37446,6 +37501,32 @@ F7B7-D46E + + Psycho Dream (Japan) + + Invincibility (blinking) + DDB7-8D6D + + + Infinite time + DD7F-7407 + + + Infinite magic + 69BE-77DF + + + Hit anywhere + 6DDD-E71F + 6DD4-EDCF + 6DD7-EF3F + 6DD0-E74F + + + Best weapon on pick-up + CBC7-74AD + + Push-Over (USA) @@ -40927,6 +41008,49 @@ Secret of Mana (USA) + + Protection from most hits (disable to kill enemies) + 8208-776D + + + Enemies die instantly + CD7E-7D67 + DD7E-7DA7 + DD7E-7FD7 + + + Hit anywhere + 40A7-6765 + 402C-0F60 + + + Level 99 after first enemy + B606-7F6F + DD78-5F64 + + + Max weapon damage + BA0A-5404 + CB0A-54D4 + + + Change screens to max out Strength, Agility, Constitution, Intelligence and Wisdom + DD03-ED04 + + + Weapon bar never decreases + 82A0-6466 + 82E0-0FD4 + + + Walk through walls + DD85-A7D1 + DD85-64A1 + + + Everything is free + 6D06-7F6F + Strength for level 16 is 90 9C06-81AD @@ -40973,11 +41097,11 @@ DDE8-E9C4 - Cup of wishes costs nothing + Cup Of Wishes costs nothing DDEC-E9C4 - Medical herb costs nothing + Medical Herb costs nothing DDEC-E944 @@ -40985,20 +41109,20 @@ DDE7-7047 - Hair ribbon costs nothing + Hair Ribbon costs nothing DDE8-E144 - Rabite cap costs nothing + Rabite Cap costs nothing DDE8-E1C4 - Faerie walnut costs nothing + Faerie Walnut costs nothing DDEC-E0C4 DDEC-E034 - Royal jam costs nothing + Royal Jam costs nothing DDEC-E044 @@ -41009,14 +41133,6 @@ Staying at Neko's costs nothing instead of 30 DDAB-E715 - - Protection from most hits (Switch off to kill enemies) - 8208-776D - - - Change screens to max out Strength, Agility, Constitution, Intelligence and Wisdom - DD03-ED04 - Start with 255 GP EE28-EDAF @@ -46605,6 +46721,14 @@ Infinite shots for most weapons A689-0FD7 + + Hit anywhere (cannot use whip to grab onto things, press Y to moon jump instead) + B428-AFA4 + C728-A4D4 + DD2C-A764 + 6D20-A7A4 + 6D21-AF64 + Fully powered whip with first power-up DD24-AFD7 @@ -46620,7 +46744,7 @@ EE26-6767 - Have maxed out hearts with each heart pick-up + Max hearts on pick-up DD2B-6D07 @@ -52461,6 +52585,14 @@ Automatic and infinite continues 82A6-4FA4 + + Hit anywhere - P1 + 6D69-149F + + + Hit anywhere - P2 + 6D6f-1F9F + Leonardo is replaced by Rat King DCCA-1405 @@ -52592,6 +52724,14 @@ One hit kills (disable when you reach Shredder's first fight) 6D6C-0F2F + + Hit anywhere - P1 + EA66-67AA + + + Hit anywhere - P2 + EA6B-67AA + Start with 1 life instead of 3 DD28-67D9 @@ -54966,14 +55106,12 @@ Ultimate Mortal Kombat 3 (USA) - Invincibility (throws disable CPU) - C132-CDBF - 1432-CD2F - 2D32-CFFF - D032-CF9F - 6D32-CFBF - 0D32-CF2F + Invincibility (throws damage CPU) + 3D3C-C79F 6D33-3DBF + 7D38-CDFF + DF3C-C7BF + E138-CD9F Infinite health - P1 @@ -56585,6 +56723,13 @@ Always win - P1 7B86-84A4 + + Hit anywhere - P1 + 7DFE-776D + ADFE-746D + DDFE-74AD + FDFE-77DD + Win a draw - P1 D409-8F04 @@ -56639,6 +56784,16 @@ World Heroes 2 (USA) + + Invincibility - P1 + 1D82-AF6D + 1D83-0F64 + + + Invincibility - P2 + 1D82-0D0D + 1D84-DD04 + Infinite health - P1 7E057480 @@ -56651,6 +56806,16 @@ Infinite time 7E052C99 + + Hit anywhere - P1 + 6D8A-07DD + 6D8F-D7D4 + + + Hit anywhere - P2 + 6D82-AD0D + 6D83-0D04 + One win wins the match - P1 7E057002 diff --git a/bsnes/nall/snes/cartridge.hpp b/bsnes/nall/snes/cartridge.hpp index 9d591488..5d84e290 100755 --- a/bsnes/nall/snes/cartridge.hpp +++ b/bsnes/nall/snes/cartridge.hpp @@ -125,7 +125,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { if(type == TypeGameBoy) { xml << "\n"; if(gameboy_ram_size(data, size) > 0) { - xml << " \n"; + xml << " \n"; } xml << "\n"; xmlMemoryMap = xml.transform("'", "\""); @@ -159,7 +159,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { xml << " \n"; xml << " \n"; } else if(has_cx4) { - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -178,9 +178,9 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { xml << " \n"; xml << " \n"; - xml << " \n"; + xml << " \n"; xml << " \n"; - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -205,7 +205,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { xml << " \n"; if(ram_size > 0) { - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { @@ -226,7 +226,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { xml << " \n"; if(ram_size > 0) { - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { @@ -244,7 +244,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { xml << " \n"; if(ram_size > 0) { - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -252,14 +252,14 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { } } else if(mapper == ExHiROM) { xml << " \n"; - xml << " \n"; - xml << " \n"; - xml << " \n"; - xml << " \n"; + xml << " \n"; + xml << " \n"; + xml << " \n"; + xml << " \n"; xml << " \n"; if(ram_size > 0) { - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; if((rom_size > 0x200000) || (ram_size > 32 * 1024)) { @@ -277,10 +277,10 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { xml << " \n"; xml << " \n"; xml << " \n"; - xml << " \n"; - xml << " \n"; + xml << " \n"; + xml << " \n"; xml << " \n"; - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -301,11 +301,11 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { xml << " \n"; xml << " \n"; xml << " \n"; - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -315,12 +315,12 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { xml << " \n"; } else if(mapper == BSCLoROM) { xml << " \n"; - xml << " \n"; - xml << " \n"; - xml << " \n"; - xml << " \n"; + xml << " \n"; + xml << " \n"; + xml << " \n"; + xml << " \n"; xml << " \n"; - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -336,7 +336,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { xml << " \n"; xml << " \n"; xml << " \n"; - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -373,7 +373,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { xml << " \n"; xml << " \n"; xml << " \n"; - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -383,7 +383,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { xml << " \n"; xml << " \n"; xml << " \n"; - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -411,7 +411,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { } if(has_dsp1) { - xml << " \n"; + xml << " \n"; if(dsp1_mapper == DSP1LoROM1MB) { xml << " \n"; xml << " \n"; @@ -444,7 +444,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { } if(has_dsp2) { - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -457,7 +457,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { } if(has_dsp3) { - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -470,7 +470,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { } if(has_dsp4) { - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -490,7 +490,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { } if(has_st010) { - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; @@ -507,7 +507,7 @@ SNESCartridge::SNESCartridge(const uint8_t *data, unsigned size) { } if(has_st011) { - xml << " \n"; + xml << " \n"; xml << " \n"; xml << " \n"; xml << " \n"; diff --git a/bsnes/snes/Makefile b/bsnes/snes/Makefile index d61ec1a1..30096db4 100755 --- a/bsnes/snes/Makefile +++ b/bsnes/snes/Makefile @@ -5,7 +5,7 @@ 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_objects += snes-obc1 snes-st0018 snes-sufamiturbo -snes_objects += snes-msu1 snes-serial snes-link +snes_objects += snes-msu1 snes-link objects += $(snes_objects) ifeq ($(profile),accuracy) @@ -54,5 +54,4 @@ 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-sufamiturbo.o: $(snes)/chip/sufamiturbo/sufamiturbo.cpp $(snes)/chip/sufamiturbo/* 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/* diff --git a/bsnes/snes/alt/cpu/cpu.cpp b/bsnes/snes/alt/cpu/cpu.cpp index 7bca1c35..aaa14830 100755 --- a/bsnes/snes/alt/cpu/cpu.cpp +++ b/bsnes/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/bsnes/snes/alt/cpu/cpu.hpp b/bsnes/snes/alt/cpu/cpu.hpp index e7946af8..3a36b349 100755 --- a/bsnes/snes/alt/cpu/cpu.hpp +++ b/bsnes/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 : unsigned { DramRefresh, HdmaRun, - ControllerLatch, }; }; nall::priority_queue queue; diff --git a/bsnes/snes/alt/cpu/mmio.cpp b/bsnes/snes/alt/cpu/mmio.cpp index 1c23a751..09bd7bc0 100755 --- a/bsnes/snes/alt/cpu/mmio.cpp +++ b/bsnes/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/bsnes/snes/alt/cpu/timing.cpp b/bsnes/snes/alt/cpu/timing.cpp index 8210cd33..88577db2 100755 --- a/bsnes/snes/alt/cpu/timing.cpp +++ b/bsnes/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/bsnes/snes/cartridge/cartridge.cpp b/bsnes/snes/cartridge/cartridge.cpp index cfbb70a1..6b447db1 100755 --- a/bsnes/snes/cartridge/cartridge.cpp +++ b/bsnes/snes/cartridge/cartridge.cpp @@ -29,13 +29,12 @@ void Cartridge::load(Mode cartridge_mode, const lstring &xml_list) { has_obc1 = false; has_st0018 = false; has_msu1 = false; - has_serial = false; has_link = false; nvram.reset(); parse_xml(xml_list); -//print(xml_list[0], "\n\n"); + print(xml_list[0], "\n\n"); if(ram_size > 0) { ram.map(allocate(ram_size, 0xff), ram_size); diff --git a/bsnes/snes/cartridge/cartridge.hpp b/bsnes/snes/cartridge/cartridge.hpp index 42d2948a..c43dafcb 100755 --- a/bsnes/snes/cartridge/cartridge.hpp +++ b/bsnes/snes/cartridge/cartridge.hpp @@ -46,7 +46,6 @@ public: readonly has_obc1; readonly has_st0018; readonly has_msu1; - readonly has_serial; readonly has_link; struct NonVolatileRAM { @@ -115,9 +114,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/bsnes/snes/cartridge/xml.cpp b/bsnes/snes/cartridge/xml.cpp index 4af33957..5202c31a 100755 --- a/bsnes/snes/cartridge/xml.cpp +++ b/bsnes/snes/cartridge/xml.cpp @@ -49,7 +49,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 +72,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 +83,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 +92,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 +120,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({ hex<4>(value), ":", name }); } @@ -162,15 +161,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 +178,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); @@ -213,8 +212,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); } mapping.append(m); } @@ -238,8 +237,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 +246,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 +255,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); @@ -289,11 +288,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 = NECDSP::Revision::uPD7725; - if(attr.content == "upd96050") necdsp.revision = NECDSP::Revision::uPD96050; + if(attr.name == "model") { + if(attr.content == "uPD7725" ) necdsp.revision = NECDSP::Revision::uPD7725; + if(attr.content == "uPD96050") necdsp.revision = 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") { @@ -378,24 +377,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 = { 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({ "Warning: Hitachi DSP program ", program, " is missing." }); + system.interface->message({ "Warning: Hitachi DSP data ", dataROM, " is missing." }); } else if(fp.size() != 1024 * 3) { - system.interface->message({ "Warning: Hitachi DSP program ", program, " is of the wrong file size." }); + system.interface->message({ "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 +416,7 @@ void Cartridge::xml_parse_hitachidsp(xml_element &root) { foreach(n, hash) filehash.append(hex<2>(n)); if(sha256 != filehash) { - system.interface->message({ "Warning: Hitachi DSP program ", program, " SHA256 sum is incorrect." }); + system.interface->message({ "Warning: Hitachi DSP data ", dataROM, " SHA256 sum is incorrect." }); } } @@ -425,25 +424,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({ &HitachiDSP::rom_read, &hitachidsp }, { &HitachiDSP::rom_write, &hitachidsp }); + if(node.name == "rom") { + foreach(leaf, node.element) { + if(leaf.name == "map") { + Mapping m({ &HitachiDSP::rom_read, &hitachidsp }, { &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({ &HitachiDSP::dsp_read, &hitachidsp }, { &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({ &HitachiDSP::dsp_read, &hitachidsp }, { &HitachiDSP::dsp_write, &hitachidsp }); - foreach(attr, leaf.attribute) { - if(attr.name == "address") xml_parse_address(m, attr.content); - } - mapping.append(m); - } } } @@ -458,8 +461,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); } @@ -510,8 +513,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 +524,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 +534,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); @@ -607,7 +610,7 @@ void Cartridge::xml_parse_spc7110(xml_element &root) { Mapping m({ &SPC7110::mcu_read, &spc7110 }, { &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); } @@ -624,7 +627,7 @@ 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) { @@ -633,8 +636,8 @@ void Cartridge::xml_parse_spc7110(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); } @@ -697,17 +700,13 @@ 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; } @@ -722,6 +721,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); diff --git a/bsnes/snes/cheat/cheat.cpp b/bsnes/snes/cheat/cheat.cpp index 4a51c4a8..ccf25136 100755 --- a/bsnes/snes/cheat/cheat.cpp +++ b/bsnes/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; } } } @@ -62,25 +62,16 @@ uint8 Cheat::read(unsigned addr) const { } void Cheat::init() { - bus.reader[0xff] = [](unsigned addr) { - bus.reader[cheat.lookup[addr]](bus.target[addr]); - return cheat.read(addr); - }; - - bus.writer[0xff] = [](unsigned addr, uint8 data) { - return bus.writer[cheat.lookup[addr]](bus.target[addr], data); - }; - - 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/bsnes/snes/cheat/cheat.hpp b/bsnes/snes/cheat/cheat.hpp index af1c0705..8e608029 100755 --- a/bsnes/snes/cheat/cheat.hpp +++ b/bsnes/snes/cheat/cheat.hpp @@ -10,6 +10,7 @@ struct CheatCode { class Cheat : public linear_vector { public: enum class Type : unsigned { ProActionReplay, GameGenie }; + uint8 *override; bool enabled() const; void enable(bool); @@ -24,7 +25,6 @@ public: static bool encode(string&, unsigned, uint8, Type); private: - uint8 *lookup; bool system_enabled; bool code_enabled; bool cheat_enabled; diff --git a/bsnes/snes/chip/chip.hpp b/bsnes/snes/chip/chip.hpp index d3d1ad2c..37be5782 100755 --- a/bsnes/snes/chip/chip.hpp +++ b/bsnes/snes/chip/chip.hpp @@ -17,7 +17,6 @@ struct Coprocessor : Processor { #include #include #include -#include #include void Coprocessor::step(unsigned clocks) { diff --git a/bsnes/snes/chip/serial/serial.cpp b/bsnes/snes/chip/serial/serial.cpp deleted file mode 100755 index 4f3d1e61..00000000 --- a/bsnes/snes/chip/serial/serial.cpp +++ /dev/null @@ -1,107 +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_coprocessors(); - 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_coprocessors(); - 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"); - } - - bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial }); - bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, { &Serial::mmio_read, &serial }, { &Serial::mmio_write, &serial }); -} - -void Serial::unload() { - if(opened()) close(); -} - -void Serial::power() { - reset(); -} - -void Serial::reset() { - create(Serial::Enter, baudrate() * 8); -} - -} diff --git a/bsnes/snes/chip/serial/serial.hpp b/bsnes/snes/chip/serial/serial.hpp deleted file mode 100755 index 361f79c8..00000000 --- a/bsnes/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/bsnes/snes/chip/serial/serialization.cpp b/bsnes/snes/chip/serial/serialization.cpp deleted file mode 100755 index 6a897c70..00000000 --- a/bsnes/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/bsnes/snes/controller/controller.cpp b/bsnes/snes/controller/controller.cpp index 8753c562..9091b21b 100755 --- a/bsnes/snes/controller/controller.cpp +++ b/bsnes/snes/controller/controller.cpp @@ -8,6 +8,7 @@ namespace SNES { #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(); diff --git a/bsnes/snes/controller/controller.hpp b/bsnes/snes/controller/controller.hpp index 8e71fb06..73327129 100755 --- a/bsnes/snes/controller/controller.hpp +++ b/bsnes/snes/controller/controller.hpp @@ -32,3 +32,4 @@ struct Controller : Processor { #include "mouse/mouse.hpp" #include "superscope/superscope.hpp" #include "justifier/justifier.hpp" +#include "serial/serial.hpp" diff --git a/bsnes/snes/controller/justifier/justifier.cpp b/bsnes/snes/controller/justifier/justifier.cpp index 8043dad8..dd4c2e1f 100755 --- a/bsnes/snes/controller/justifier/justifier.cpp +++ b/bsnes/snes/controller/justifier/justifier.cpp @@ -1,12 +1,20 @@ #ifdef CONTROLLER_CPP void Justifier::enter() { + unsigned prev = 0; while(true) { - static unsigned prev = 0; unsigned next = cpu.vcounter() * 1364 + cpu.hcounter(); - if(next >= target && prev < target) { - iobit(0); - iobit(1); + + 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) { @@ -25,18 +33,14 @@ void Justifier::enter() { x2 = max(-16, min(256 + 16, nx2)); y2 = max(-16, min(240 + 16, ny2)); } - - if(active == 0) { - bool offscreen = (x1 < 0 || y1 < 0 || x1 >= 256 || y1 >= (ppu.overscan() ? 240 : 225)); - target = offscreen ? -1 : y1 * 1364 + (x1 + 24) * 4; - } else { - bool offscreen = (x2 < 0 || y2 < 0 || x2 >= 256 || y2 >= (ppu.overscan() ? 240 : 225)); - target = offscreen ? -1 : y2 * 1364 + (x2 + 24) * 4; - } + } 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(4); + step(2); } } @@ -117,8 +121,6 @@ Justifier::Justifier(bool port, bool chained) : Controller(port), chained(chaine y2 = 240 / 2; } - target = -1; - trigger1 = false; trigger2 = false; diff --git a/bsnes/snes/controller/justifier/justifier.hpp b/bsnes/snes/controller/justifier/justifier.hpp index 40920ebe..82591471 100755 --- a/bsnes/snes/controller/justifier/justifier.hpp +++ b/bsnes/snes/controller/justifier/justifier.hpp @@ -12,7 +12,6 @@ struct Justifier : Controller { bool active; signed x1, x2; signed y1, y2; - signed target; bool trigger1, trigger2; bool start1, start2; }; diff --git a/bsnes/snes/controller/serial/serial.cpp b/bsnes/snes/controller/serial/serial.cpp new file mode 100755 index 00000000..c3ba69c7 --- /dev/null +++ b/bsnes/snes/controller/serial/serial.cpp @@ -0,0 +1,146 @@ +#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(); + } + } +} + +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/bsnes/snes/controller/serial/serial.hpp b/bsnes/snes/controller/serial/serial.hpp new file mode 100755 index 00000000..2a68ba53 --- /dev/null +++ b/bsnes/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/bsnes/snes/controller/superscope/superscope.cpp b/bsnes/snes/controller/superscope/superscope.cpp index 1d4074e0..46d5734f 100755 --- a/bsnes/snes/controller/superscope/superscope.cpp +++ b/bsnes/snes/controller/superscope/superscope.cpp @@ -5,17 +5,25 @@ //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) { - static unsigned prev = 0; unsigned next = cpu.vcounter() * 1364 + cpu.hcounter(); - if(next >= target && prev < target) { - iobit(0); - iobit(1); + + 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) { @@ -27,11 +35,14 @@ void SuperScope::enter() { 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)); - target = offscreen ? -1 : y * 1364 + (x + 24) * 4; + } 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(4); + step(2); } } @@ -101,7 +112,6 @@ SuperScope::SuperScope(bool port) : Controller(port) { //center cursor onscreen x = 256 / 2; y = 240 / 2; - target = -1; trigger = false; cursor = false; diff --git a/bsnes/snes/controller/superscope/superscope.hpp b/bsnes/snes/controller/superscope/superscope.hpp index 637b8891..a7a90b71 100755 --- a/bsnes/snes/controller/superscope/superscope.hpp +++ b/bsnes/snes/controller/superscope/superscope.hpp @@ -8,7 +8,7 @@ struct SuperScope : Controller { bool latched; unsigned counter; - signed x, y, target; + signed x, y; bool trigger; bool cursor; diff --git a/bsnes/snes/cpu/timing/joypad.cpp b/bsnes/snes/cpu/timing/joypad.cpp index d5a2b40d..6e15346e 100755 --- a/bsnes/snes/cpu/timing/joypad.cpp +++ b/bsnes/snes/cpu/timing/joypad.cpp @@ -6,8 +6,6 @@ void CPU::step_auto_joypad_poll() { status.auto_joypad_active = status.auto_joypad_counter <= 15; if(status.auto_joypad_active && status.auto_joypad_poll) { - synchronize_controllers(); - if(status.auto_joypad_counter == 0) { input.port1->latch(1); input.port2->latch(1); diff --git a/bsnes/snes/cpu/timing/timing.cpp b/bsnes/snes/cpu/timing/timing.cpp index 5504e05e..c569e94e 100755 --- a/bsnes/snes/cpu/timing/timing.cpp +++ b/bsnes/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); diff --git a/bsnes/snes/input/input.cpp b/bsnes/snes/input/input.cpp index 359b3b35..89199030 100755 --- a/bsnes/snes/input/input.cpp +++ b/bsnes/snes/input/input.cpp @@ -17,6 +17,7 @@ void Input::connect(bool port, Input::Device id) { 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; } switch(port) { diff --git a/bsnes/snes/input/input.hpp b/bsnes/snes/input/input.hpp index 08d3ad06..13ef46e1 100755 --- a/bsnes/snes/input/input.hpp +++ b/bsnes/snes/input/input.hpp @@ -7,6 +7,7 @@ struct Input { SuperScope, Justifier, Justifiers, + Serial, }; enum class JoypadID : unsigned { diff --git a/bsnes/snes/memory/memory-inline.hpp b/bsnes/snes/memory/memory-inline.hpp index 7a9e3407..70503bea 100755 --- a/bsnes/snes/memory/memory-inline.hpp +++ b/bsnes/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/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index d022cf97..dd5cbbdc 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -1,7 +1,7 @@ namespace SNES { namespace Info { static const char Name[] = "bsnes"; - static const char Version[] = "079.06"; + static const char Version[] = "080"; static const unsigned SerializerVersion = 21; } } diff --git a/bsnes/snes/system/serialization.cpp b/bsnes/snes/system/serialization.cpp index 660ce8f4..d97f73b7 100755 --- a/bsnes/snes/system/serialization.cpp +++ b/bsnes/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/bsnes/snes/system/system.cpp b/bsnes/snes/system/system.cpp index 079f1127..37118b43 100755 --- a/bsnes/snes/system/system.cpp +++ b/bsnes/snes/system/system.cpp @@ -82,7 +82,6 @@ void System::init(Interface *interface_) { obc1.init(); st0018.init(); msu1.init(); - serial.init(); link.init(); video.init(); @@ -121,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(); @@ -146,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(); } @@ -183,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() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2); @@ -192,7 +188,6 @@ 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(); @@ -223,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() == Cartridge::Mode::SuperGameBoy) cpu.coprocessors.append(&icd2); @@ -232,7 +226,6 @@ 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(); diff --git a/bsnes/ui-libsnes/libsnes.cpp b/bsnes/ui-libsnes/libsnes.cpp index 6153de1f..2a7786db 100755 --- a/bsnes/ui-libsnes/libsnes.cpp +++ b/bsnes/ui-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)device); + SNES::input.connect(port, (SNES::Input::Device)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(SNES::Controller::Port1, SNES::Input::Device::Joypad); + SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad); } void snes_term(void) { diff --git a/bsnes/ui-libsnes/libsnes.hpp b/bsnes/ui-libsnes/libsnes.hpp index 39e2f75a..5d7f50e1 100755 --- a/bsnes/ui-libsnes/libsnes.hpp +++ b/bsnes/ui-libsnes/libsnes.hpp @@ -10,13 +10,14 @@ extern "C" { #define SNES_PORT_1 0 #define SNES_PORT_2 1 -#define SNES_DEVICE_NONE 0 -#define SNES_DEVICE_JOYPAD 1 -#define SNES_DEVICE_MULTITAP 2 -#define SNES_DEVICE_MOUSE 3 -#define SNES_DEVICE_SUPER_SCOPE 4 -#define SNES_DEVICE_JUSTIFIER 5 -#define SNES_DEVICE_JUSTIFIERS 6 +#define SNES_DEVICE_NONE 0 +#define SNES_DEVICE_JOYPAD 1 +#define SNES_DEVICE_MULTITAP 2 +#define SNES_DEVICE_MOUSE 3 +#define SNES_DEVICE_SUPER_SCOPE 4 +#define SNES_DEVICE_JUSTIFIER 5 +#define SNES_DEVICE_JUSTIFIERS 6 +#define SNES_DEVICE_SERIAL_CABLE 7 #define SNES_DEVICE_ID_JOYPAD_B 0 #define SNES_DEVICE_ID_JOYPAD_Y 1 diff --git a/bsnes/ui/general/main-window.cpp b/bsnes/ui/general/main-window.cpp index 1231eb50..4b18eab8 100755 --- a/bsnes/ui/general/main-window.cpp +++ b/bsnes/ui/general/main-window.cpp @@ -82,9 +82,13 @@ void MainWindow::create() { systemPort2Justifiers.setText("Justifiers"); systemPort2.append(systemPort2Justifiers); + systemPort2Serial.setText("Serial Cable"); + systemPort2.append(systemPort2Serial); + RadioItem::group( systemPort2None, systemPort2Gamepad, systemPort2Multitap, systemPort2Mouse, - systemPort2SuperScope, systemPort2Justifier, systemPort2Justifiers + systemPort2SuperScope, systemPort2Justifier, systemPort2Justifiers, + systemPort2Serial ); append(system); @@ -235,6 +239,7 @@ void MainWindow::create() { if(config.controller.port2 == 4) systemPort2SuperScope.setChecked(); if(config.controller.port2 == 5) systemPort2Justifier.setChecked(); if(config.controller.port2 == 6) systemPort2Justifiers.setChecked(); + if(config.controller.port2 == 7) systemPort2Serial.setChecked(); if(config.video.scale == 1) settingsVideoMode1x.setChecked(); if(config.video.scale == 2) settingsVideoMode2x.setChecked(); @@ -289,6 +294,7 @@ void MainWindow::create() { systemPort2SuperScope.onTick = []() { config.controller.port2 = 4; utility.setControllers(); }; systemPort2Justifier.onTick = []() { config.controller.port2 = 5; utility.setControllers(); }; systemPort2Justifiers.onTick = []() { config.controller.port2 = 6; utility.setControllers(); }; + systemPort2Serial.onTick = []() { config.controller.port2 = 7; utility.setControllers(); }; settingsVideoMode1x.onTick = []() { utility.setScale(1); }; settingsVideoMode2x.onTick = []() { utility.setScale(2); }; diff --git a/bsnes/ui/general/main-window.hpp b/bsnes/ui/general/main-window.hpp index 03f24764..c3b52f4c 100755 --- a/bsnes/ui/general/main-window.hpp +++ b/bsnes/ui/general/main-window.hpp @@ -23,6 +23,7 @@ struct MainWindow : TopLevelWindow { RadioItem systemPort2SuperScope; RadioItem systemPort2Justifier; RadioItem systemPort2Justifiers; + RadioItem systemPort2Serial; Menu settings; Menu settingsVideoMode; diff --git a/bsnes/ui/main.cpp b/bsnes/ui/main.cpp index 444b7ffc..9f99e162 100755 --- a/bsnes/ui/main.cpp +++ b/bsnes/ui/main.cpp @@ -118,6 +118,7 @@ void Application::main(int argc, char **argv) { if(SNES::cartridge.loaded()) { if(application.pause == true || (config.settings.focusPolicy == 0 && mainWindow.focused() == false)) { + audio.clear(); usleep(20 * 1000); continue; } diff --git a/bsnes/ui/utility/utility.cpp b/bsnes/ui/utility/utility.cpp index 21009d31..198f561a 100755 --- a/bsnes/ui/utility/utility.cpp +++ b/bsnes/ui/utility/utility.cpp @@ -54,6 +54,7 @@ void Utility::setControllers() { case 4: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::SuperScope); break; case 5: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Justifier); break; case 6: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Justifiers); break; + case 7: SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Serial); break; } }